1
0
Эх сурвалжийг харах

Support Windows MSVC (#855)

The following changes have been made:
1. Replace deprecated functions with new standard functions
2. Add corresponding MSVC functions for non-standard functions 
3. Remove warnings about unsafe functions
4. CMAKE: modify find pack Libevent and openssl 
5. Modify include files
6. Use pthread4W
7. Modify socket in windows
8. Add CI - github action
8.1. msvc
8.2. mingw
10. The database:
9.1. sqlite, pgsql, hiredis, mongo  is test compiled.
9.2. mysql, isnot test compiled.
11. The applications、server can be compiled and run successfully! 
12. Add vcpkg manifest mode in cmake.
Kang Lin 3 жил өмнө
parent
commit
40c99db6ba
56 өөрчлөгдсөн 2806 нэмэгдсэн , 476 устгасан
  1. 96 0
      .github/workflows/mingw.yml
  2. 110 0
      .github/workflows/msvc.yml
  3. 4 2
      .gitignore
  4. 40 22
      CMakeLists.txt
  5. 91 0
      cmake/CMakeCPack.cmake
  6. 12 0
      cmake/CMakeCPackOptions.cmake.in
  7. 51 0
      cmake/coturnConfig.cmake.in
  8. 1 1
      src/CMakeLists.txt
  9. 1 1
      src/apps/CMakeLists.txt
  10. 51 25
      src/apps/common/CMakeLists.txt
  11. 378 18
      src/apps/common/apputils.c
  12. 23 1
      src/apps/common/apputils.h
  13. 72 6
      src/apps/common/ns_turn_utils.c
  14. 11 5
      src/apps/common/ns_turn_utils.h
  15. 1 1
      src/apps/common/stun_buffer.c
  16. 562 0
      src/apps/common/win/getopt.c
  17. 105 0
      src/apps/common/win/getopt.h
  18. 9 1
      src/apps/natdiscovery/CMakeLists.txt
  19. 6 1
      src/apps/natdiscovery/natdiscovery.c
  20. 9 1
      src/apps/oauth/CMakeLists.txt
  21. 4 1
      src/apps/oauth/oauth.c
  22. 9 1
      src/apps/peer/CMakeLists.txt
  23. 6 0
      src/apps/peer/mainudpserver.c
  24. 2 2
      src/apps/peer/udpserver.c
  25. 0 5
      src/apps/peer/udpserver.h
  26. 68 23
      src/apps/relay/CMakeLists.txt
  27. 33 2
      src/apps/relay/dbdrivers/dbd_sqlite.c
  28. 37 13
      src/apps/relay/dtls_listener.c
  29. 7 12
      src/apps/relay/http_server.c
  30. 30 30
      src/apps/relay/libtelnet.c
  31. 627 116
      src/apps/relay/mainrelay.c
  32. 12 7
      src/apps/relay/mainrelay.h
  33. 36 31
      src/apps/relay/netengine.c
  34. 20 22
      src/apps/relay/ns_ioalib_engine_impl.c
  35. 32 6
      src/apps/relay/turn_admin_server.c
  36. 2 2
      src/apps/relay/turn_ports.c
  37. 24 15
      src/apps/relay/userdb.c
  38. 9 1
      src/apps/rfc5769/CMakeLists.txt
  39. 5 1
      src/apps/rfc5769/rfc5769check.c
  40. 9 1
      src/apps/stunclient/CMakeLists.txt
  41. 10 2
      src/apps/stunclient/stunclient.c
  42. 9 1
      src/apps/uclient/CMakeLists.txt
  43. 23 2
      src/apps/uclient/mainuclient.c
  44. 36 37
      src/apps/uclient/startuclient.c
  45. 13 14
      src/apps/uclient/uclient.c
  46. 17 9
      src/client/CMakeLists.txt
  47. 5 2
      src/client/ns_turn_ioaddr.c
  48. 11 7
      src/client/ns_turn_msg.c
  49. 10 3
      src/ns_turn_defs.h
  50. 18 5
      src/server/CMakeLists.txt
  51. 2 4
      src/server/ns_turn_allocation.c
  52. 19 4
      src/server/ns_turn_ioalib.h
  53. 3 4
      src/server/ns_turn_maps_rtcp.c
  54. 4 5
      src/server/ns_turn_server.c
  55. 1 1
      src/server/ns_turn_server.h
  56. 20 0
      vcpkg.json

+ 96 - 0
.github/workflows/mingw.yml

@@ -0,0 +1,96 @@
+name: mingw 
+
+on: [push]
+
+jobs:
+  build:
+    name: build
+
+    strategy:
+      matrix:
+        os: [windows-latest]
+        # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
+        BUILD_TYPE: [Release, Debug]
+        BUILD_SHARED_LIBS: [OFF]
+
+    defaults:
+      run:
+        shell: cmd
+        
+    runs-on: ${{ matrix.os }}
+    env:
+      BUILD_TYPE:  ${{ matrix.BUILD_TYPE }}
+      SOURCE_DIR:  ${{github.workspace}}\.cache\source
+      TOOSL_DIR:   ${{github.workspace}}\.cache\tools
+      INSTALL_DIR: ${{github.workspace}}\.cache\install_mingw_2022_02_15
+
+    steps:
+    - uses: actions/checkout@v2
+      #with:
+        #fetch-depth: 0
+            
+    - name: pacman
+      env:
+        PATH: C:\msys64\usr\bin
+      run: |
+        C:\msys64\usr\bin\pacman.exe -S --noconfirm ^
+            mingw-w64-x86_64-cmake ^
+            mingw-w64-x86_64-make ^
+            mingw-w64-x86_64-nsis ^
+            mingw-w64-x86_64-gcc ^
+            mingw-w64-x86_64-zlib ^
+            mingw-w64-x86_64-openssl ^
+            mingw-w64-x86_64-libevent ^
+            mingw-w64-x86_64-sqlite3 ^
+            mingw-w64-x86_64-hiredis ^
+            mingw-w64-x86_64-postgresql ^
+            git base-devel
+
+    - name: make_directory
+      run: |
+        cmake -E make_directory ${{env.SOURCE_DIR}}
+        cmake -E make_directory ${{env.TOOSL_DIR}}
+        cmake -E make_directory ${{env.INSTALL_DIR}}
+    
+    - name: Cache installed
+      uses: actions/cache@v2
+      id: cache-installed
+      with:
+        path: |
+          ${{env.INSTALL_DIR}}
+        key: coturn-cache-installed-mingw
+
+    - name: build coturn
+      working-directory: ${{github.workspace}}
+      env:
+        MSYSTEM: MINGW64
+        PATH: C:\msys64\mingw64\bin;C:\msys64\usr\bin
+      run: |
+        cmake -E make_directory build
+        cd build
+        cmake .. -G"MinGW Makefiles" ^
+            -DBUILD_SHARED_LIBS=${{matrix.BUILD_SHARED_LIBS}} ^
+            -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} ^
+            -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/build/install
+        cmake --build . --config ${{matrix.BUILD_TYPE}}
+        cmake --build . --config ${{matrix.BUILD_TYPE}} --target install
+
+    - name: Package
+      if: ${{ matrix.BUILD_TYPE == 'Release' }}
+      working-directory: ${{github.workspace}}\build
+      run: |
+        copy /Y ${{env.INSTALL_DIR}}\bin\*.dll install\bin
+        copy /Y ${{env.INSTALL_DIR}}\lib\*.dll install\bin
+        copy /Y ${{env.RUNVCPKG_VCPKG_ROOT}}\installed\${{env.RUNVCPKG_VCPKG_TRIPLET_OUT}}\bin\*.dll install\bin
+        7z a coturn_windows_mingw.zip ${{github.workspace}}\build\install\*
+        cmake --build . --config ${{matrix.BUILD_TYPE}} --target package
+
+    - name: update 
+      if: ${{ matrix.BUILD_TYPE == 'Release' }}
+      uses: actions/upload-artifact@v2
+      with:
+        name: coturn_mingw_${{ matrix.os }}
+        path: |
+          ${{github.workspace}}\build\coturn_windows_mingw.zip
+          ${{github.workspace}}\build\coturn*.exe
+          ${{github.workspace}}\build\coturn*.md5

+ 110 - 0
.github/workflows/msvc.yml

@@ -0,0 +1,110 @@
+name: msvc
+
+on: [push]
+
+jobs:
+  compile:
+    name: ${{matrix.os}}-vc-${{matrix.VCPKG_PLATFORM_TOOLSET}}-${{matrix.CMAKE_GENERATOR_PLATFORM}}-${{matrix.BUILD_TYPE}}-${{matrix.BUILD_SHARED_LIBS}}
+
+    strategy:
+      matrix:
+        BUILD_TYPE: [Release, Debug]
+        BUILD_SHARED_LIBS: [OFF, ON]
+        #VCPKG_PLATFORM_TOOLSET: [v143, v142, v141]
+        CMAKE_GENERATOR_PLATFORM: [x64, Win32]
+        os: [windows-latest]
+        include:
+          # MSVC 2022
+          - triplet: x64-windows
+            VCPKG_PLATFORM_TOOLSET: v143
+            CMAKE_GENERATOR_PLATFORM: x64
+
+          - triplet: x86-windows
+            VCPKG_PLATFORM_TOOLSET: v143
+            CMAKE_GENERATOR_PLATFORM: Win32
+
+          # MSVC 2019
+          - triplet: x86-windows
+            VCPKG_PLATFORM_TOOLSET: v142
+            CMAKE_GENERATOR_PLATFORM: Win32
+ 
+          # MSVC 2017
+          - triplet: x86-windows
+            VCPKG_PLATFORM_TOOLSET: v141
+            CMAKE_GENERATOR_PLATFORM: Win32
+ 
+    runs-on: ${{matrix.os}}
+
+    env:
+      SOURCE_DIR:  ${{github.workspace}}\.cache\source
+      TOOLS_DIR:   ${{github.workspace}}\.cache\tools
+      INSTALL_DIR: ${{github.workspace}}\.cache\install_msvc_${{matrix.triplet}}_${{matrix.BUILD_TYPE}}
+      VCPKGGITCOMMITID: acc3bcf76b84ae5041c86ab55fe138ae7b8255c7
+      VCPKG_PLATFORM_TOOLSET: ${{matrix.VCPKG_PLATFORM_TOOLSET}}
+      CMAKE_GENERATOR_PLATFORM: ${{matrix.CMAKE_GENERATOR_PLATFORM}}
+
+    defaults:
+      run:
+        shell: cmd
+
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        fetch-depth: 0
+
+    - name: make directory
+      run: |
+        cmake -E make_directory ${{env.SOURCE_DIR}}
+        cmake -E make_directory ${{env.TOOLS_DIR}}
+        cmake -E make_directory ${{env.INSTALL_DIR}}
+
+    - name: Cache installed
+      uses: actions/cache@v2
+      id: cache-installed
+      with:
+        path: |
+          ${{env.INSTALL_DIR}}
+        key: coturn-cache-installed-${{matrix.os}}-vc${{matrix.VCPKG_PLATFORM_TOOLSET}}-${{matrix.triplet}}-${{matrix.BUILD_TYPE}}
+
+    - name: run-vcpkg
+      uses: lukka/run-vcpkg@v10
+      with:
+        # If not using a submodule for vcpkg sources, this specifies which commit
+        # id must be checkout from a Git repo. It must not set if using a submodule
+        # for vcpkg.
+        vcpkgGitCommitId: '${{ env.VCPKGGITCOMMITID }}'
+        # Since the cache must be invalidated when content of the vcpkg.json file changes, let's
+        # compute its hash and append this to the computed cache's key.
+        appendedCacheKey: coturn-msvc-${{matrix.os}}-vc${{matrix.VCPKG_PLATFORM_TOOLSET}}-${{matrix.triplet}}-${{matrix.BUILD_TYPE}}-${{env.VCPKGGITCOMMITID}}
+
+    - name: build coturn
+      run: |
+        cmake -E make_directory ${{github.workspace}}/build
+        cd ${{github.workspace}}/build
+        cmake ${{github.workspace}} ^
+            -A ${{matrix.CMAKE_GENERATOR_PLATFORM}} ^
+            -T ${{matrix.VCPKG_PLATFORM_TOOLSET}} ^
+            -DWITH_MYSQL=OFF ^
+            -DBUILD_SHARED_LIBS=${{matrix.BUILD_SHARED_LIBS}} ^
+            -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} ^
+            -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/build/install ^
+            -DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake
+        cmake --build . --config ${{matrix.BUILD_TYPE}}
+        cmake --build . --config ${{matrix.BUILD_TYPE}} --target install
+
+    - name: Package
+      if: ${{ matrix.BUILD_TYPE == 'Release' }}
+      working-directory: ${{github.workspace}}\build
+      run: |
+        7z a coturn_windows_msvc.zip ${{github.workspace}}\build\install\*
+        cmake --build . --config ${{matrix.BUILD_TYPE}} --target package
+
+    - name: update 
+      if: ${{ matrix.BUILD_TYPE == 'Release' }}
+      uses: actions/upload-artifact@v2
+      with:
+        name: coturn_msvc-${{matrix.VCPKG_PLATFORM_TOOLSET}}-${{matrix.CMAKE_GENERATOR_PLATFORM}}-${{matrix.BUILD_SHARED_LIBS}}
+        path: |
+          ${{github.workspace}}\build\coturn_windows_msvc.zip
+          ${{github.workspace}}\build\coturn*.exe
+          ${{github.workspace}}\build\coturn*.md5

+ 4 - 2
.gitignore

@@ -1,15 +1,18 @@
 /Makefile
 /bin/
-build
+*build*/
 include
 lib
 sqlite
 examples/ca/CA.pl
 .vscode
+.idea
+.vs/
 
 # This file is used to ignore files which are generated
 # ----------------------------------------------------------------------------
 
+*.bak
 *~
 *.autosave
 *.a
@@ -80,4 +83,3 @@ Thumbs.db
 # --------
 *.dll
 *.exe
-

+ 40 - 22
CMakeLists.txt

@@ -1,12 +1,15 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 cmake_minimum_required(VERSION 3.5)
 
 project(coturn)
+#set(CMAKE_INCLUDE_CURRENT_DIR ON)
+#set(CMAKE_C_STANDARD 11)
+#set(CMAKE_C_STANDARD_REQUIRED ON)
 
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
 # TODO: Modify this when the version is released
-SET(BUILD_VERSION "4.5.2")
+SET(BUILD_VERSION "4.6.0")
 
 option(FUZZER "Build oss-fuzz fuzzing" OFF)
 
@@ -34,7 +37,12 @@ IF(EXISTS "${CMAKE_SOURCE_DIR}/.git")
         SET(BUILD_VERSION ${GIT_VERSION})
     ENDIF()
 ENDIF()
-message("BUILD_VERSION:${BUILD_VERSION}")
+string(FIND ${BUILD_VERSION} / BUILD_VERSION_POS REVERSE)
+if(BUILD_VERSION_POS GREATER -1)
+    math(EXPR BUILD_VERSION_POS "${BUILD_VERSION_POS} + 1")
+    string(SUBSTRING ${BUILD_VERSION} ${BUILD_VERSION_POS} -1 BUILD_VERSION)
+endif()
+message("BUILD_VERSION:${BUILD_VERSION};${_BUILD_VERSION}")
 set(VERSION ${BUILD_VERSION})
 
 if(NOT DEFINED CMAKE_BUILD_TYPE)
@@ -55,11 +63,20 @@ IF(MSVC)
     ENDIF(WIN32_USE_MP)
     add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
     add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
+    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
 ENDIF(MSVC)
 
-IF(APPLE)
-    add_compile_definitions("TURN_NO_THREAD_BARRIERS=1")
-ENDIF()
+SET(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libs")
+if (BUILD_SHARED_LIBS)
+    add_definitions(-DBUILD_SHARED_LIBS)
+    if (CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW)
+       # Just setting CMAKE_POSITION_INDEPENDENT_CODE should be enough to set
+       # -fPIC for GCC but sometimes it still doesn't get set, so make sure it
+       # does.
+       add_definitions("-fPIC")
+    endif()
+    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+endif(BUILD_SHARED_LIBS)
 
 include(CMakePackageConfigHelpers)
 include(GNUInstallDirs)
@@ -68,18 +85,6 @@ include(CheckIncludeFile)
 include(CheckIncludeFileCXX)
 include(CheckFunctionExists)
 
-# Create install runtime target
-add_custom_target(install-runtime
-  COMMAND
-     "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=Runtime 
-     -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake"
-)
-# Create uninstall runtime target
-add_custom_target(uninstall-runtime
-  COMMAND
-     "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=Runtime 
-     -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
-)
 # Create will be delete files
 CONFIGURE_FILE(
     "${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
@@ -92,6 +97,19 @@ ADD_CUSTOM_TARGET(uninstall
 
 add_subdirectory(src)
 
+OPTION(BUILD_TEST "Build test" OFF)
+if(BUILD_TEST)
+    add_subdirectory(test)
+endif(BUILD_TEST)
+
+CONFIGURE_FILE(
+    "${CMAKE_SOURCE_DIR}/cmake/coturnConfig.cmake.in"
+    "${CMAKE_BINARY_DIR}/coturnConfig.cmake"
+    IMMEDIATE @ONLY)
+install(FILES "${CMAKE_BINARY_DIR}/coturnConfig.cmake"
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+        COMPONENT Development)
+
 install(DIRECTORY man DESTINATION .
     COMPONENT Runtime)
 install(DIRECTORY turndb/
@@ -115,11 +133,11 @@ install(FILES examples/etc/turnserver.conf
     RENAME turnserver.conf.default
     )
 install(DIRECTORY
-            examples/etc
-            examples/scripts
-    DESTINATION share/examples/turnserver
-    PATTERN "rfc5769.sh" EXCLUDE
+        examples
+    DESTINATION share
+        COMPONENT examples
     )
+include(cmake/CMakeCPack.cmake)
 
 if(FUZZER)
     if (NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")

+ 91 - 0
cmake/CMakeCPack.cmake

@@ -0,0 +1,91 @@
+# Author: Kang Lin <[email protected]>
+
+configure_file("${CMAKE_SOURCE_DIR}/cmake/CMakeCPackOptions.cmake.in"
+	"${CMAKE_BINARY_DIR}/CMakeCPackOptions.cmake" @ONLY)
+set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_BINARY_DIR}/CMakeCPackOptions.cmake")
+
+# Generate .txt license file for CPack (PackageMaker requires a file extension)
+configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/LICENSE.txt @ONLY)
+
+SET(CPACK_BINARY_ZIP "ON")
+
+set(CPACK_SOURCE_IGNORE_FILES
+    ${CMAKE_SOURCE_DIR}/build
+    ${CMAKE_SOURCE_DIR}/.cache
+    ${CMAKE_SOURCE_DIR}/.git
+    ${CMAKE_SOURCE_DIR}/.github
+    ${CMAKE_SOURCE_DIR}/.gitignore
+    ${CMAKE_SOURCE_DIR}/.dockerignore
+    ${CMAKE_SOURCE_DIR}/CMakeCache.txt)
+
+set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR}")
+set(CPACK_TOPLEVEL_TAG "${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_PROCESSOR}")
+string(TOLOWER ${CMAKE_PROJECT_NAME} CMAKE_PROJECT_NAME_lower)
+set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME_lower}_${BUILD_VERSION}_${CPACK_SYSTEM_NAME}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME_lower}_${BUILD_VERSION}_${CPACK_SYSTEM_NAME}")
+#set(CPACK_PACKAGE_DIRECTORY ${CMAKE_BINARY_DIR}/package)
+
+set(CPACK_PACKAGE_NAME "coturn")
+set(CPACK_PACKAGE_VENDOR "coturn")
+set(CPACK_PACKAGE_VERSION ${BUILD_VERSION})
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "coturn: Free open source implementation of TURN and STUN Server")
+#set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
+#set(CPACK_RESOURCE_FILE_WELCOME )
+set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/LICENSE.txt")
+set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/coturn/coturn")
+set(CPACK_PACKAGE_CONTACT "misi <[email protected]>")
+
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "coturn")
+set(CPACK_PACKAGE_CHECKSUM "MD5")
+
+############### Debian ###################
+if(UNIX)
+	set(CPACK_BINARY_DEB ON)
+endif()
+set(CPACK_DEBIAN_PACKAGE_SOURCE coturn)
+set(CPACK_DEBIAN_PACKAGE_MAINTAINER "misi <[email protected]>")
+#set(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
+set(CPACK_DEBIAN_PACKAGE_SECTION "main")
+set(CPACK_DEBIAN_PACKAGE_PREDEPENDS "debhelper (>= 6), cmake (>= 2.8.0), dh-systemd (>= 1.5)")
+#set(CMAKE_INSTALL_RPATH )
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
+#set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY ">=")
+#set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
+#    "${CMAKE_CURRENT_SOURCE_DIR}/prerm;${CMAKE_CURRENT_SOURCE_DIR}/postrm")
+############### Debian ###################
+
+#set(CPACK_PACKAGE_EXECUTABLES turnadmin turnclient)
+#set(CPACK_CREATE_DESKTOP_LINKS turnadmin turnclient)
+
+############### NSIS ###################
+if(WIN32)
+	set(CPACK_BINARY_NSIS ON)
+endif()
+#set(CPACK_NSIS_INSTALL_ROOT "$LOCALAPPDATA")
+set(CPACK_NSIS_MODIFY_PATH ON)
+set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
+#set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources\\\\coturn_Install.bmp")
+#set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources\\\\coturn_Icon_96px.ico")
+#set(CPACK_NSIS_MUI_UNICON "${CMAKE_SOURCE_DIR}/resource\\\\coturn_Icon_96px.ico")
+############### NSIS ###################
+
+#set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE )
+set(CPACK_COMPONENTS_ALL Runtime Development)
+
+SET(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT Runtime)
+include(InstallRequiredSystemLibraries)
+include(CPackComponent)
+include(CPack)
+
+cpack_add_component(Development
+    DISPLAY_NAME  "Development"
+    DESCRIPTION   "Development"
+    DEPENDS Runtime
+    )
+
+cpack_add_component(Runtime
+    DISPLAY_NAME  "Runtime"
+    DESCRIPTION   "Runtime"
+    )

+ 12 - 0
cmake/CMakeCPackOptions.cmake.in

@@ -0,0 +1,12 @@
+# Author: Kang Lin <[email protected]>
+
+# This file is configured at cmake time, and loaded at cpack time.
+# To pass variables to cpack from cmake, they must be configured in this file.
+
+if("${CPACK_GENERATOR}" STREQUAL "PackageMaker")
+	if(CMAKE_PACKAGE_QTGUI)
+		set(CPACK_PACKAGE_DEFAULT_LOCATION "/Applications")
+	else()
+		set(CPACK_PACKAGE_DEFAULT_LOCATION "/usr")
+	endif()
+endif()

+ 51 - 0
cmake/coturnConfig.cmake.in

@@ -0,0 +1,51 @@
+# - Try to find coturn
+#
+#  Usage from an external project:
+#    In your CMakeLists.txt, add these lines:
+#
+#    find_package(coturn)
+#    target_link_libraries(MY_TARGET_NAME ${coturn_LIBRARIES})
+#  
+#  This file will define the following variables:
+#    coturn_FOUND: True if find coturn, other false
+#    coturn_LIBRARIES:  The list of all imported targets for coturn components
+#
+# Author: Kang Lin <[email protected]>
+
+include(FindPackageHandleStandardArgs)
+
+if (NOT coturn_FIND_COMPONENTS)
+    set(coturn_FIND_COMPONENTS
+        turncommon
+        turnclient
+        turn_server
+	)
+endif()
+
+get_filename_component(_coturn_module_paths "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE)
+
+set(_coturn_FIND_PARTS_REQUIRED)
+if (coturn_FIND_REQUIRED)
+    set(_coturn_FIND_PARTS_REQUIRED REQUIRED)
+endif()
+set(_coturn_FIND_PARTS_QUIET)
+if (coturn_FIND_QUIETLY)
+    set(_coturn_FIND_PARTS_QUIET QUIET)
+endif()
+
+foreach(module ${coturn_FIND_COMPONENTS})
+    find_package(${module}
+        ${_coturn_FIND_PARTS_QUIET}
+        ${_coturn_FIND_PARTS_REQUIRED}
+        PATHS ${_coturn_module_paths} NO_DEFAULT_PATH
+    )
+    if(${module}_FOUND)
+        list(APPEND coturn_LIBRARIES coturn::${module})
+    endif()
+    list(APPEND required "${module}_FOUND")  
+endforeach()
+
+# Run checks via find_package_handle_standard_args
+find_package_handle_standard_args(coturn
+	FOUND_VAR coturn_FOUND
+	REQUIRED_VARS ${required})

+ 1 - 1
src/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(coturn)
 

+ 1 - 1
src/apps/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 add_subdirectory(common)
 add_subdirectory(natdiscovery)

+ 51 - 25
src/apps/common/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turncommon)
 
@@ -15,18 +15,39 @@ set(HEADER_FILES
     stun_buffer.h
     )
 
-if(NOT WIN32)
-    set(COMMON_LIBS pthread)
+if(MSVC)
+    list(APPEND COMMON_INCLUDE_DIR $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/apps/common/win>)
+    list(APPEND SOURCE_FILES win/getopt.c)
+    list(APPEND HEADER_FILES win/getopt.h)
 endif()
-set(libevent_components core extra openssl)
-if(NOT WIN32)
-    list(APPEND libevent_components pthreads)
+
+if(MSVC OR MINGW)
+    list(APPEND COMMON_DEFINED WINDOWS)
+	list(APPEND COMMON_LIBS Ws2_32 netapi32)
+endif()
+
+find_package(OpenSSL REQUIRED COMPONENTS Crypto SSL)
+list(APPEND COMMON_LIBS OpenSSL::SSL OpenSSL::Crypto)
+
+if(MSVC)
+	find_package(pthreads REQUIRED)
+	list(APPEND COMMON_LIBS PThreads4W::PThreads4W)
+else()
+    find_package(Threads REQUIRED)
+	list(APPEND COMMON_LIBS Threads::Threads)
 endif()
-find_package(Libevent COMPONENTS ${libevent_components})
+
+find_package(Libevent CONFIG)
 if(Libevent_FOUND)
-    foreach(_libevent_com ${libevent_components})
-        list(APPEND COMMON_LIBS Libevent::${_libevent_com})
-    endforeach()
+    list(APPEND COMMON_LIBS libevent::core libevent::extra libevent::openssl)
+else()
+    find_package(Libevent MODULE)
+    if(Libevent_FOUND)
+        list(APPEND COMMON_LIBS ${Libevent_LIBRARIES})
+        list(APPEND COMMON_INCLUDE_DIR ${Libevent_INCLUDE_DIRS})
+    else()
+        message(FATAL_ERROR "Must set Libevent")
+    endif()
 endif()
 
 find_package(hiredis)
@@ -37,18 +58,15 @@ if(hiredis_FOUND)
 else()
     list(APPEND COMMON_DEFINED TURN_NO_HIREDIS)
 endif()
-
-find_package(OpenSSL REQUIRED Crypto SSL)
-list(APPEND COMMON_LIBS OpenSSL::Crypto)
-list(APPEND COMMON_LIBS OpenSSL::SSL)
-
 message("COMMON_LIBS:${COMMON_LIBS}")
 
-add_library(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES})
+add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${HEADER_FILES})
 
 target_link_libraries(${PROJECT_NAME} PUBLIC ${COMMON_LIBS})
 target_compile_definitions(${PROJECT_NAME} PUBLIC ${COMMON_DEFINED})
-target_compile_options(${PROJECT_NAME} PUBLIC -Wno-deprecated-declarations)
+target_compile_options(${PROJECT_NAME} PUBLIC
+	$<$<C_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
+	$<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>)
 
 # See: http://www.it1352.com/478094.html
 target_include_directories(${PROJECT_NAME} PUBLIC
@@ -60,8 +78,11 @@ target_include_directories(${PROJECT_NAME} PUBLIC
     ${COMMON_INCLUDE_DIR}
     )
 
-# Install head files
 set_target_properties(${PROJECT_NAME} PROPERTIES
+    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
+    PUBLIC_HEADER "${HEADER_FILES}"  # Install header files
     VERSION ${VERSION}
     )
 
@@ -72,26 +93,31 @@ INSTALL(TARGETS ${PROJECT_NAME}
     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
         COMPONENT Runtime
     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        COMPONENT Development
+	PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/turn"
+		COMPONENT Development
     INCLUDES DESTINATION
-        ${CMAKE_INSTALL_INCLUDEDIR}
-        ${CMAKE_INSTALL_INCLUDEDIR}/turn
-        ${CMAKE_INSTALL_INCLUDEDIR}/turn/client
+        "${CMAKE_INSTALL_INCLUDEDIR}/turn"
     )
 
 export(TARGETS ${PROJECT_NAME}
-    APPEND FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+    APPEND FILE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+    NAMESPACE coturn::
     )
 
 # Install cmake configure files
 install(EXPORT ${PROJECT_NAME}Config
-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake"
+    NAMESPACE coturn::
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+        COMPONENT Development
     )
 # Install cmake version configure file
 if(DEFINED VERSION)
     write_basic_package_version_file(
         "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
-        VERSION ${VERSION}
+        VERSION "${VERSION}"
         COMPATIBILITY AnyNewerVersion)
     install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
-        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake")
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+            COMPONENT Development)
 endif()

+ 378 - 18
src/apps/common/apputils.c

@@ -35,18 +35,39 @@
 
 #include <event2/event.h>
 
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+	|| defined(__DARWIN__) || defined(__MACH__)
+    #include <ifaddrs.h>
+    #include <getopt.h>
+    #include <libgen.h>
+#endif
+#if defined(__unix__) || defined(unix)
+    #include <pthread.h>
+    #include <sys/time.h>
+    #include <sys/resource.h>
+    #include <sys/sysinfo.h>
+#endif
+
+#if defined(WINDOWS)
+	#include <DSRole.h>
+#endif
+
+#if defined(_MSC_VER)
+	#include <direct.h>
+#else
+	#include <unistd.h>
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
+
+#include <limits.h>
 #include <locale.h>
-#include <libgen.h>
 #include <fcntl.h>
-
 #include <signal.h>
 
-#include <sys/resource.h>
 
 #if !defined(TURN_NO_SCTP) && defined(TURN_SCTP_INCLUDE)
 #include TURN_SCTP_INCLUDE
@@ -60,7 +81,7 @@ int IS_TURN_SERVER = 0;
 
 int socket_set_nonblocking(evutil_socket_t fd)
 {
-#if defined(WIN32)
+#if defined(WINDOWS)
 	unsigned long nonblocking = 1;
     ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
 #else
@@ -76,7 +97,12 @@ void read_spare_buffer(evutil_socket_t fd)
 {
 	if(fd >= 0) {
 		static char buffer[65536];
+#if defined(WINDOWS)
+        //TODO: add set no-block? by Kang Lin <[email protected]>
+		recv(fd, buffer, sizeof(buffer), 0);
+#else
 		recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT);
+#endif
 	}
 }
 
@@ -115,6 +141,29 @@ int set_sock_buf_size(evutil_socket_t fd, int sz0)
 	return 0;
 }
 
+int socket_init()
+{
+#if defined(WINDOWS)
+	{
+		WORD wVersionRequested;
+		WSADATA wsaData;
+		int e;
+
+		/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
+		wVersionRequested = MAKEWORD(2, 2);
+
+		e = WSAStartup(wVersionRequested, &wsaData);
+		if (e != 0) {
+			/* Tell the user that we could not find a usable */
+			/* Winsock DLL.                                  */
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "WSAStartup failed with error: %d\n", e);
+			return 1;
+		}
+	}
+#endif
+	return 0;
+}
+
 int socket_tcp_set_keepalive(evutil_socket_t fd,SOCKET_TYPE st)
 {
 	UNUSED_ARG(st);
@@ -147,7 +196,7 @@ int socket_set_reusable(evutil_socket_t fd, int flag, SOCKET_TYPE st)
 		return -1;
 	else {
 
-#if defined(WIN32)
+#if defined(WINDOWS)
 		int use_reuseaddr = IS_TURN_SERVER;
 #else
 		int use_reuseaddr = 1;
@@ -691,12 +740,15 @@ int handle_socket_error(void) {
      * Must close connection.
      */
     return 0;
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+	|| defined(__DARWIN__) || defined(__MACH__)
   case EHOSTDOWN:
     /* Host is down.
      * Just ignore, might be an attacker
      * sending fake ICMP messages.
      */
     return 1;
+#endif
   case ECONNRESET:
   case ECONNREFUSED:
     /* Connection reset by peer. */
@@ -731,6 +783,259 @@ char *skip_blanks(char* s)
 	return s;
 }
 
+#if defined(_MSC_VER)
+
+LARGE_INTEGER getFILETIMEoffset()
+{
+	SYSTEMTIME s;
+	FILETIME f;
+	LARGE_INTEGER t;
+
+	s.wYear = 1970;
+	s.wMonth = 1;
+	s.wDay = 1;
+	s.wHour = 0;
+	s.wMinute = 0;
+	s.wSecond = 0;
+	s.wMilliseconds = 0;
+	SystemTimeToFileTime(&s, &f);
+	t.QuadPart = f.dwHighDateTime;
+	t.QuadPart <<= 32;
+	t.QuadPart |= f.dwLowDateTime;
+	return (t);
+}
+
+int clock_gettime(int X, struct timeval* tv)
+{
+	LARGE_INTEGER           t;
+	FILETIME                f;
+	double                  microseconds;
+	static LARGE_INTEGER    offset;
+	static double           frequencyToMicroseconds;
+	static int              initialized = 0;
+	static BOOL             usePerformanceCounter = FALSE;
+
+	if (!initialized) {
+		LARGE_INTEGER performanceFrequency;
+		initialized = 1;
+		usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
+		if (usePerformanceCounter) {
+			QueryPerformanceCounter(&offset);
+			frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
+		}
+		else {
+			offset = getFILETIMEoffset();
+			frequencyToMicroseconds = 10.;
+		}
+	}
+	if (usePerformanceCounter) QueryPerformanceCounter(&t);
+	else {
+		GetSystemTimeAsFileTime(&f);
+		t.QuadPart = f.dwHighDateTime;
+		t.QuadPart <<= 32;
+		t.QuadPart |= f.dwLowDateTime;
+	}
+
+	t.QuadPart -= offset.QuadPart;
+	microseconds = (double)t.QuadPart / frequencyToMicroseconds;
+	t.QuadPart = microseconds;
+	tv->tv_sec = t.QuadPart / 1000000;
+	tv->tv_usec = t.QuadPart % 1000000;
+	return 0;
+}
+
+int gettimeofday(struct timeval* tp, void* tzp)
+{
+	time_t clock;
+	struct tm tm;
+	SYSTEMTIME wtm;
+
+	GetLocalTime(&wtm);
+	tm.tm_year = wtm.wYear - 1900;
+	tm.tm_mon = wtm.wMonth - 1;
+	tm.tm_mday = wtm.wDay;
+	tm.tm_hour = wtm.wHour;
+	tm.tm_min = wtm.wMinute;
+	tm.tm_sec = wtm.wSecond;
+	tm.tm_isdst = -1;
+	clock = mktime(&tm);
+	tp->tv_sec = clock;
+	tp->tv_usec = wtm.wMilliseconds * 1000;
+
+	return (0);
+}
+
+char* dirname(char* path)
+{
+	char drive[_MAX_DRIVE];
+	char dir[_MAX_DIR];
+
+	errno_t err = _splitpath_s(path,
+		drive, _MAX_DRIVE,
+		dir, _MAX_DIR,
+		NULL, 0,
+		NULL, 0);
+	if (err)
+	{
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "split path fail: %d", err);
+		return NULL;
+	}
+
+	int n = strlen(drive) + strlen(dir);
+	if (n > 0)
+		path[n] = 0;
+	else
+		return NULL;
+	return path;
+}
+#endif
+
+#if defined(WINDOWS)
+int getdomainname(char* name, size_t len)
+{
+	DSROLE_PRIMARY_DOMAIN_INFO_BASIC* info;
+	DWORD dw;
+
+	dw = DsRoleGetPrimaryDomainInformation(NULL,
+		     DsRolePrimaryDomainInfoBasic,
+		     (PBYTE*)&info);
+	if (dw != ERROR_SUCCESS)
+	{
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "DsRoleGetPrimaryDomainInformation: %u\n", dw);
+		return -1;
+	}
+
+	do {
+		if (info->DomainForestName)
+		{
+			char* pszOut = NULL;
+			int nOutSize = 0;
+			if (_WTA(info->DomainForestName, wcslen(info->DomainForestName), &pszOut, &nOutSize))
+			{
+				int n = nOutSize - 1;
+				if (nOutSize > len - 1)
+				{
+					n = len - 1;
+				}
+				strncpy(name, pszOut, n);
+				name[n] = 0;
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "DomainForestName: %s\n", pszOut);
+			}
+			else
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "wchar convert to char fail");
+
+			free(pszOut);
+			break;
+		} else {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "DomainForestName is NULL\n");
+		}
+
+		if (info->DomainNameDns)
+		{
+			char* pszOut = NULL;
+			int nOutSize = 0;
+			if (_WTA(info->DomainNameDns, wcslen(info->DomainNameDns), &pszOut, &nOutSize))
+			{
+				int n = nOutSize - 1;
+				if (nOutSize > len - 1)
+				{
+					n = len - 1;
+				}
+				strncpy(name, pszOut, n);
+				name[n] = 0;
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "DomainNameDns: %s\n", pszOut);
+			}
+			else
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "wchar convert to char fail");
+
+			free(pszOut);
+			break;
+		} else {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "DomainNameDns is NULL\n");
+		}
+
+		if (info->DomainNameFlat)
+		{
+			char* pszOut = NULL;
+			int nOutSize = 0;
+			if (_WTA(info->DomainNameFlat, wcslen(info->DomainNameFlat), &pszOut, &nOutSize))
+			{
+				int n = nOutSize - 1;
+				if (nOutSize > len - 1)
+				{
+					n = len - 1;
+				}
+				strncpy(name, pszOut, n);
+				name[n] = 0;
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "DomainNameFlat: %s\n", pszOut);
+			}
+			else
+				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "wchar convert to char fail");
+
+			free(pszOut);
+		} else {
+			TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "DomainNameFlat is NULL\n");
+			return -2;
+		}
+	} while (0);
+
+	DsRoleFreeMemory(info);
+	return 0;
+}
+
+/*!
+ * \brief convert char to wchar
+ * 
+ * \param pszInBuf: input buffer of wchar string 
+ * \param nInSize: size of wchar string
+ * \param pszOutBuf: output buffer of char string
+ * \param pnOutSize: size of char string
+ * \return 
+ */
+wchar_t* _ATW(__in char* pszInBuf, __in int nInSize, __out wchar_t** pszOutBuf, __out int* pnOutSize)
+{
+	if (!pszInBuf || !pszOutBuf || !pnOutSize || nInSize <= 0) return NULL;
+	// Get buffer size
+	*pnOutSize = MultiByteToWideChar(NULL, NULL, pszInBuf, nInSize, *pszOutBuf, 0);
+	if (*pnOutSize == 0) return NULL;
+	(*pnOutSize)++;
+	*pszOutBuf = malloc((*pnOutSize) * sizeof(wchar_t));
+	memset((void*)*pszOutBuf, 0, sizeof(wchar_t) * (*pnOutSize));
+	if (MultiByteToWideChar(NULL, NULL, pszInBuf, nInSize, *pszOutBuf, *pnOutSize) == 0)
+	{
+		free(*pszOutBuf);
+		return NULL;
+	}
+	else return *pszOutBuf;
+}
+
+/*!
+ * \brief convert wchar to char
+ * 
+ * \param pszInBuf: input buffer of char string 
+ * \param nInSize: size of char string
+ * \param pszOutBuf: output buffer of wchar string
+ * \param pnOutSize: size of wchar string
+ * \return 
+ */
+char* _WTA(__in wchar_t* pszInBuf, __in int nInSize, __out char** pszOutBuf, __out int* pnOutSize)
+{
+	if (!pszInBuf || !pszOutBuf || !pnOutSize || nInSize <= 0) return NULL;
+	*pnOutSize = WideCharToMultiByte(NULL, NULL, pszInBuf, nInSize, *pszOutBuf, 0, NULL, NULL);
+	if (*pnOutSize == 0) return NULL;
+	(*pnOutSize)++;
+	*pszOutBuf = malloc(*pnOutSize * sizeof(char));
+	memset((void*)*pszOutBuf, 0, sizeof(char) * (*pnOutSize));
+	if (WideCharToMultiByte(NULL, NULL, pszInBuf, nInSize, *pszOutBuf, *pnOutSize, NULL, NULL) == 0)
+	{
+		free(*pszOutBuf);
+		return NULL;
+	}
+	else return *pszOutBuf;
+}
+
+#endif
+
 //////////////////// Config file search //////////////////////
 
 #define Q(x) #x
@@ -751,18 +1056,29 @@ static char *c_execdir=NULL;
 void set_execdir(void)
 {
   /* On some systems, this may give us the execution path */
-  char *_var = getenv("_");
-  if(_var && *_var) {
+	char *_var = NULL;
+#if defined(_MSC_VER)
+	char szPath[MAX_PATH];
+	if (!GetModuleFileNameA(NULL, szPath, MAX_PATH))
+	{
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "GetModuleFileName failed(%d)\n", GetLastError());
+		return;
+	}
+	_var = szPath;
+#elif defined(__unix__)
+	_var = getenv("_");
+#endif
+	if (_var && *_var) {
     _var = strdup(_var);
-    char *edir=_var;
-    if(edir[0]!='.') 
-      edir = strstr(edir,"/");
-    if(edir && *edir)
-      edir = dirname(edir);
+		char *edir = _var;
+		if (edir[0] != '.')
+			edir = strstr(edir, "/");
+		if (edir && *edir)
+            edir = dirname(edir);
     else
-      edir = dirname(_var);
-    if(c_execdir)
-      free(c_execdir);
+        edir = dirname(_var);
+		if (c_execdir)
+            free(c_execdir);
     c_execdir = strdup(edir);
     free(_var);
   }
@@ -880,10 +1196,12 @@ char* find_config_file(const char *config_file, int print_file_name)
 
 void ignore_sigpipe(void)
 {
+#if defined(__linux__) || defined(__APPLE__)
 	/* Ignore SIGPIPE from TCP sockets */
 	if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
 		perror("Cannot set SIGPIPE handler");
 	}
+#endif
 }
 
 static uint64_t turn_getRandTime(void) {
@@ -899,16 +1217,34 @@ static uint64_t turn_getRandTime(void) {
   return current_mstime;
 }
 
+void turn_srandom(void)
+{
+#if defined(WINDOWS)
+	srand((unsigned int)(turn_getRandTime() + (unsigned int)((long)(&turn_getRandTime))));
+#else
+	srandom((unsigned int)(turn_getRandTime() + (unsigned int)((long)(&turn_getRandTime))));
+#endif
+}
+
 unsigned long set_system_parameters(int max_resources)
 {
-	srandom((unsigned int) (turn_getRandTime() + (unsigned int)((long)(&turn_getRandTime))));
+	turn_srandom();
+
 	setlocale(LC_ALL, "C");
 
 	build_base64_decoding_table();
 
 	ignore_sigpipe();
 
-	if(max_resources) {
+	if (max_resources) {
+#if defined(WINDOWS)
+		int num = 0;
+		//TODO: get max socket? by KangLin <[email protected]>
+
+		num = _getmaxstdio();
+		return num;
+#elif defined(__linux__) || defined(__APPLE__)
+	
 		struct rlimit rlim;
 		if(getrlimit(RLIMIT_NOFILE, &rlim)<0) {
 			perror("Cannot get system limit");
@@ -919,11 +1255,35 @@ unsigned long set_system_parameters(int max_resources)
 			}
 			return (unsigned long)rlim.rlim_cur;
 		}
+	
+#endif
 	}
 
 	return 0;
 }
 
+unsigned long get_system_number_of_cpus()
+{
+#if defined(WINDOWS)
+	SYSTEM_INFO sysInfo;
+	GetSystemInfo(&sysInfo);
+	TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "System cpu num is %d\n", sysInfo.dwNumberOfProcessors);
+	TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "System enable num is 0x%X\n", sysInfo.dwActiveProcessorMask);
+	return sysInfo.dwNumberOfProcessors;
+#else
+    #if defined(_SC_NPROCESSORS_ONLN)
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "System cpu num is %d \n", sysconf(_SC_NPROCESSORS_CONF));
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "System enable num is %d\n", sysconf(_SC_NPROCESSORS_ONLN));
+		return sysconf(_SC_NPROCESSORS_CONF);
+	#else
+		//GNU way
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "System cpu num is %d\n", get_nprocs_conf());
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_DEBUG, "System enable num is %d\n", get_nprocs());
+		return get_nprocs_conf();
+	#endif
+#endif
+}
+
 ////////////////////// Base 64 ////////////////////////////
 
 static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',

+ 23 - 1
src/apps/common/apputils.h

@@ -159,7 +159,7 @@ typedef struct _oauth_key_data_raw oauth_key_data_raw;
 
 ///////////////////////// Sockets ///////////////////////////////
 
-#if defined(WIN32)
+#if defined(WINDOWS)
 /** Do the platform-specific call needed to close a socket returned from
     socket() or accept(). */
 #define socket_closesocket(s) closesocket(s)
@@ -173,6 +173,7 @@ void read_spare_buffer(evutil_socket_t fd);
 
 int set_sock_buf_size(evutil_socket_t fd, int sz);
 
+int socket_init();
 int socket_set_reusable(evutil_socket_t fd, int reusable, SOCKET_TYPE st);
 int sock_bind_to_device(evutil_socket_t fd, const unsigned char* ifname);
 int socket_set_nonblocking(evutil_socket_t fd);
@@ -198,6 +199,7 @@ int get_raw_socket_ttl(evutil_socket_t fd, int family);
 
 void ignore_sigpipe(void);
 unsigned long set_system_parameters(int max_resources);
+unsigned long get_system_number_of_cpus();
 
 ///////////////////////// MTU //////////////////////////
 
@@ -216,6 +218,22 @@ int get_socket_mtu(evutil_socket_t fd, int family, int verbose);
 
 char *skip_blanks(char* s);
 
+#if defined(_MSC_VER)
+    #define CLOCK_REALTIME 0
+	int clock_gettime(int X, struct timeval* tv);
+	int gettimeofday(struct timeval* tp, void* tzp);
+
+	char* dirname(char* path);
+#endif
+
+#if defined(WINDOWS)
+	int getdomainname(char* name, size_t len);
+	// wchar convert to char
+	char* _WTA(__in wchar_t* pszInBufBuf, __in int nInSize, __out char** pszOutBuf, __out int* pnOutSize);
+	// char convert to wchar
+	wchar_t* _ATW(__in char* pszInBuf, __in int nInSize, __out wchar_t** pszOutBuf, __out int* pnOutSize);
+#endif
+
 ////////////////// File search ////////////////////////
 
 char* find_config_file(const char *config_file, int print_file_name);
@@ -246,6 +264,10 @@ void convert_oauth_key_data_raw(const oauth_key_data_raw *raw, oauth_key_data *o
 
 struct event_base *turn_event_base_new(void);
 
+//////////// Random /////////////////////
+
+void turn_srandom(void);
+
 ///////////////////////////////////////////////////////
 
 #ifdef __cplusplus

+ 72 - 6
src/apps/common/ns_turn_utils.c

@@ -38,7 +38,11 @@
 
 #include <pthread.h>
 
-#include <syslog.h>
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+    || defined(__DARWIN__) || defined(__MACH__)
+	#include <syslog.h>
+#endif
+
 #include <stdarg.h>
 
 #include <stdlib.h>
@@ -48,6 +52,8 @@
 
 ////////// LOG TIME OPTIMIZATION ///////////
 
+static volatile int _log_file_line_set = 0;
+
 static volatile turn_time_t log_start_time = 0;
 volatile int _log_time_value_set = 0;
 volatile turn_time_t _log_time_value = 0;
@@ -157,6 +163,8 @@ static char* str_fac[]={"LOG_AUTH","LOG_CRON","LOG_DAEMON",
 			"LOG_AUTHPRIV","LOG_SYSLOG",
 			0};
 
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+		|| defined(__DARWIN__) || defined(__MACH__)
 static int int_fac[]={LOG_AUTH ,  LOG_CRON , LOG_DAEMON ,
 		    LOG_KERN , LOG_LOCAL0 , LOG_LOCAL1 ,
 		    LOG_LOCAL2 , LOG_LOCAL3 , LOG_LOCAL4 , LOG_LOCAL5 ,
@@ -176,18 +184,21 @@ static int str_to_syslog_facility(char *s)
 	}
 	return -1;
 }
-
+#endif
 void set_syslog_facility(char *val)
 {
 	if(val == NULL){
 		return;
 	}
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+		|| defined(__DARWIN__) || defined(__MACH__)
 	int tmp = str_to_syslog_facility(val);
 	if(tmp == -1){
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: invalid syslog-facility value (%s); ignored.\n", val);
 		return;
 	}
 	syslog_facility = tmp;
+#endif
 }
 
 #if defined(TURN_LOG_FUNC_IMPL)
@@ -292,6 +303,11 @@ void set_logfile(const char *fn)
 	}
 }
 
+void set_log_file_line(int set)
+{
+	_log_file_line_set = set;
+}
+
 void reset_rtpprintf(void)
 {
 	log_lock();
@@ -361,9 +377,12 @@ static void set_log_file_name_func(char *base, char *f, size_t fsz)
 
 static void sighup_callback_handler(int signum)
 {
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+	|| defined(__DARWIN__) || defined(__MACH__)
 	if(signum == SIGHUP) {
 		to_reset_log_file = 1;
 	}
+#endif
 }
 
 static void set_rtpfile(void)
@@ -377,7 +396,12 @@ static void set_rtpfile(void)
 	if(to_syslog) {
 		return;
 	} else if (!_rtpfile) {
+
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+		|| defined(__DARWIN__) || defined(__MACH__)
 		signal(SIGHUP, sighup_callback_handler);
+#endif
+
 		if(log_fn_base[0]) {
 			if(!strcmp(log_fn_base,"syslog")) {
 				_rtpfile = stdout;
@@ -516,6 +540,8 @@ void rollover_logfile(void)
 
 static int get_syslog_level(TURN_LOG_LEVEL level)
 {
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+	|| defined(__DARWIN__) || defined(__MACH__)
 	switch(level) {
 	case TURN_LOG_LEVEL_CONTROL:
 		return LOG_NOTICE;
@@ -527,9 +553,21 @@ static int get_syslog_level(TURN_LOG_LEVEL level)
 		;
 	};
 	return LOG_INFO;
+#endif
+	return level;
+}
+
+#if defined(WINDOWS)
+void err(int eval, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    TURN_LOG_FUNC(eval, format, args);
+    va_end(args);
 }
+#endif
 
-void turn_log_func_default(TURN_LOG_LEVEL level, const char* format, ...)
+void turn_log_func_default(char* file, int line, TURN_LOG_LEVEL level, const char* format, ...)
 {
 	va_list args;
 	va_start(args,format);
@@ -546,8 +584,28 @@ void turn_log_func_default(TURN_LOG_LEVEL level, const char* format, ...)
 	} else {
 		so_far += snprintf(s, sizeof(s), "%lu: ", (unsigned long)log_time());
 	}
-	so_far += snprintf(s + so_far, sizeof(s)-100, (level == TURN_LOG_LEVEL_ERROR) ? ": ERROR: " : ": ");
-	so_far += vsnprintf(s + so_far,sizeof(s) - (so_far+1), format, args);
+	if (_log_file_line_set)
+        so_far += snprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far + 1), "%s(%d):", file, line);
+
+	switch (level)
+    {
+	case TURN_LOG_LEVEL_DEBUG:
+		so_far += snprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far + 1), "DEBUG: ");
+		break;
+    case TURN_LOG_LEVEL_INFO:
+        so_far += snprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far + 1), "INFO: ");
+        break;
+    case TURN_LOG_LEVEL_CONTROL:
+        so_far += snprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far + 1), "CONTROL: ");
+        break;
+    case TURN_LOG_LEVEL_WARNING:
+        so_far += snprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far + 1), "WARNING: ");
+        break;
+    case TURN_LOG_LEVEL_ERROR:
+        so_far += snprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far + 1), "ERROR: ");
+        break;
+    }
+	so_far += vsnprintf(s + so_far, MAX_RTPPRINTF_BUFFER_SIZE - (so_far+1), format, args);
 	if(so_far > MAX_RTPPRINTF_BUFFER_SIZE+1)
 	{
 		so_far=MAX_RTPPRINTF_BUFFER_SIZE+1;
@@ -556,7 +614,15 @@ void turn_log_func_default(TURN_LOG_LEVEL level, const char* format, ...)
 		fwrite(s, so_far, 1, stdout);
 	/* write to syslog or to log file */
 	if(to_syslog) {
-		syslog(syslog_facility|get_syslog_level(level),"%s",s);
+
+#if defined(WINDOWS)
+		//TODO: add event tracing: https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing
+		// windows10: https://docs.microsoft.com/en-us/windows/win32/tracelogging/trace-logging-portal
+		printf("%s", s);
+#else
+        syslog(syslog_facility | get_syslog_level(level), "%s", s);
+#endif
+
 	} else {
 		log_lock();
 		set_rtpfile();

+ 11 - 5
src/apps/common/ns_turn_utils.h

@@ -32,8 +32,13 @@
 #define __TURN_ULIB__
 
 #if !defined(TURN_LOG_FUNC)
-//#define TURN_LOG_FUNC(level, ...) printf (__VA_ARGS__)
-#define TURN_LOG_FUNC turn_log_func_default
+#define TURN_LOG_FUNC(level, ...) turn_log_func_default(__FILE__, __LINE__, level, __VA_ARGS__)
+#endif
+
+#if defined(WINDOWS)
+    #ifndef err
+        void err(int eval, const char *format, ...);
+    #endif
 #endif
 
 #include "ns_turn_ioaddr.h"
@@ -45,7 +50,8 @@ extern "C" {
 //////////////////////// LOG //////////////////////////
 
 typedef enum {
-  TURN_LOG_LEVEL_INFO = 0,
+	TURN_LOG_LEVEL_DEBUG = 0,
+	TURN_LOG_LEVEL_INFO,
   TURN_LOG_LEVEL_CONTROL,
   TURN_LOG_LEVEL_WARNING,
   TURN_LOG_LEVEL_ERROR
@@ -65,12 +71,11 @@ void set_syslog_facility(char *val);
 
 void set_turn_log_timestamp_format(char* new_format);
 
-void turn_log_func_default(TURN_LOG_LEVEL level, const char* format, ...);
+void turn_log_func_default(char* file, int line, TURN_LOG_LEVEL level, const char* format, ...);
 
 void addr_debug_print(int verbose, const ioa_addr *addr, const char* s);
 
 /* Log */
-
 extern volatile int _log_time_value_set;
 extern volatile turn_time_t _log_time_value;
 extern int use_new_log_timestamp_format;
@@ -80,6 +85,7 @@ int vrtpprintf(TURN_LOG_LEVEL level, const char *format, va_list args);
 void reset_rtpprintf(void);
 void set_logfile(const char *fn);
 void rollover_logfile(void);
+void set_log_file_line(int set);
 
 ///////////////////////////////////////////////////////
 

+ 1 - 1
src/apps/common/stun_buffer.c

@@ -146,7 +146,7 @@ int stun_is_channel_message(stun_buffer* buf, uint16_t* chnumber, int is_padding
   size_t blen = (size_t)buf->len;
   int ret = stun_is_channel_message_str(buf->buf, &blen, chnumber, is_padding_mandatory);
   if(ret) {
-	  buf->len=(ssize_t)blen;
+	  buf->len = blen;
   }
   return ret;
 }

+ 562 - 0
src/apps/common/win/getopt.c

@@ -0,0 +1,562 @@
+/*	$OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $	*/
+/*	$NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $	*/
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <windows.h>
+
+#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int	opterr = 1;		/* if error message should be printed */
+int	optind = 1;		/* index into parent argv vector */
+int	optopt = '?';		/* character checked for validity */
+#undef	optreset		/* see getopt.h */
+#define	optreset		__mingw_optreset
+int	optreset;		/* reset getopt */
+char    *optarg;		/* argument associated with option */
+#endif
+
+#define PRINT_ERROR	((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
+#define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
+
+/* return values */
+#define	BADCH		(int)'?'
+#define	BADARG		((*options == ':') ? (int)':' : (int)'?')
+#define	INORDER 	(int)1
+
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define	EMSG		""
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+			   const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+			      const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+  (void)fprintf(stderr,"%s: ",__progname);
+  if (fmt != NULL)
+    (void)vfprintf(stderr,fmt,ap);
+  (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+  va_list ap;
+  va_start(ap,fmt);
+  _vwarnx(fmt,ap);
+  va_end(ap);
+}
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+	int c;
+
+	c = a % b;
+	while (c != 0) {
+		a = b;
+		b = c;
+		c = a % b;
+	}
+
+	return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+	char * const *nargv)
+{
+	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+	char *swap;
+
+	/*
+	 * compute lengths of blocks and number and size of cycles
+	 */
+	nnonopts = panonopt_end - panonopt_start;
+	nopts = opt_end - panonopt_end;
+	ncycle = gcd(nnonopts, nopts);
+	cyclelen = (opt_end - panonopt_start) / ncycle;
+
+	for (i = 0; i < ncycle; i++) {
+		cstart = panonopt_end+i;
+		pos = cstart;
+		for (j = 0; j < cyclelen; j++) {
+			if (pos >= panonopt_end)
+				pos -= nnonopts;
+			else
+				pos += nopts;
+			swap = nargv[pos];
+			/* LINTED const cast */
+			((char **) nargv)[pos] = nargv[cstart];
+			/* LINTED const cast */
+			((char **)nargv)[cstart] = swap;
+		}
+	}
+}
+
+/*
+ * parse_long_options --
+ *	Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int short_too)
+{
+	char *current_argv, *has_equal;
+	size_t current_argv_len;
+	int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y)                                \
+	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
+	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
+	 long_options[(_x)].val == long_options[(_y)].val)
+
+	current_argv = place;
+	match = -1;
+	ambiguous = 0;
+
+	optind++;
+
+	if ((has_equal = strchr(current_argv, '=')) != NULL) {
+		/* argument found (--option=arg) */
+		current_argv_len = has_equal - current_argv;
+		has_equal++;
+	} else
+		current_argv_len = strlen(current_argv);
+
+	for (i = 0; long_options[i].name; i++) {
+		/* find matching long option */
+		if (strncmp(current_argv, long_options[i].name,
+		    current_argv_len))
+			continue;
+
+		if (strlen(long_options[i].name) == current_argv_len) {
+			/* exact match */
+			match = i;
+			ambiguous = 0;
+			break;
+		}
+		/*
+		 * If this is a known short option, don't allow
+		 * a partial match of a single character.
+		 */
+		if (short_too && current_argv_len == 1)
+			continue;
+
+		if (match == -1)	/* partial match */
+			match = i;
+		else if (!IDENTICAL_INTERPRETATION(i, match))
+			ambiguous = 1;
+	}
+	if (ambiguous) {
+		/* ambiguous abbreviation */
+		if (PRINT_ERROR)
+			warnx(ambig, (int)current_argv_len,
+			     current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (match != -1) {		/* option found */
+		if (long_options[match].has_arg == no_argument
+		    && has_equal) {
+			if (PRINT_ERROR)
+				warnx(noarg, (int)current_argv_len,
+				     current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			return (BADARG);
+		}
+		if (long_options[match].has_arg == required_argument ||
+		    long_options[match].has_arg == optional_argument) {
+			if (has_equal)
+				optarg = has_equal;
+			else if (long_options[match].has_arg ==
+			    required_argument) {
+				/*
+				 * optional argument doesn't use next nargv
+				 */
+				optarg = nargv[optind++];
+			}
+		}
+		if ((long_options[match].has_arg == required_argument)
+		    && (optarg == NULL)) {
+			/*
+			 * Missing argument; leading ':' indicates no error
+			 * should be generated.
+			 */
+			if (PRINT_ERROR)
+				warnx(recargstring,
+				    current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			--optind;
+			return (BADARG);
+		}
+	} else {			/* unknown option */
+		if (short_too) {
+			--optind;
+			return (-1);
+		}
+		if (PRINT_ERROR)
+			warnx(illoptstring, current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (idx)
+		*idx = match;
+	if (long_options[match].flag) {
+		*long_options[match].flag = long_options[match].val;
+		return (0);
+	} else
+		return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ *	Parse argc/argv argument vector.  Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int flags)
+{
+	const char *oli;				/* option letter list index */
+	int optchar, short_too;
+	static int posixly_correct = -1;
+
+	if (options == NULL)
+		return (-1);
+
+	/*
+	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
+	 * XXX using optreset.  Work around this braindamage.
+	 */
+	if (optind == 0)
+		optind = optreset = 1;
+
+	/*
+	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
+	 * string begins with a '+'.
+	 *
+	 * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+	 *                 optreset != 0 for GNU compatibility.
+	 */
+	if (posixly_correct == -1 || optreset != 0)
+		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+	if (*options == '-')
+		flags |= FLAG_ALLARGS;
+	else if (posixly_correct || *options == '+')
+		flags &= ~FLAG_PERMUTE;
+	if (*options == '+' || *options == '-')
+		options++;
+
+	optarg = NULL;
+	if (optreset)
+		nonopt_start = nonopt_end = -1;
+start:
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc) {          /* end of argument vector */
+			place = EMSG;
+			if (nonopt_end != -1) {
+				/* do permutation, if we have to */
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			else if (nonopt_start != -1) {
+				/*
+				 * If we skipped non-options, set optind
+				 * to the first of them.
+				 */
+				optind = nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+		if (*(place = nargv[optind]) != '-' ||
+		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
+			place = EMSG;		/* found non-option */
+			if (flags & FLAG_ALLARGS) {
+				/*
+				 * GNU extension:
+				 * return non-option as argument to option 1
+				 */
+				optarg = nargv[optind++];
+				return (INORDER);
+			}
+			if (!(flags & FLAG_PERMUTE)) {
+				/*
+				 * If no permutation wanted, stop parsing
+				 * at first non-option.
+				 */
+				return (-1);
+			}
+			/* do permutation */
+			if (nonopt_start == -1)
+				nonopt_start = optind;
+			else if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				nonopt_start = optind -
+				    (nonopt_end - nonopt_start);
+				nonopt_end = -1;
+			}
+			optind++;
+			/* process next argument */
+			goto start;
+		}
+		if (nonopt_start != -1 && nonopt_end == -1)
+			nonopt_end = optind;
+
+		/*
+		 * If we have "-" do nothing, if "--" we are done.
+		 */
+		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+			optind++;
+			place = EMSG;
+			/*
+			 * We found an option (--), so if we skipped
+			 * non-options, we have to permute.
+			 */
+			if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Check long options if:
+	 *  1) we were passed some
+	 *  2) the arg is not just "-"
+	 *  3) either the arg starts with -- we are getopt_long_only()
+	 */
+	if (long_options != NULL && place != nargv[optind] &&
+	    (*place == '-' || (flags & FLAG_LONGONLY))) {
+		short_too = 0;
+		if (*place == '-')
+			place++;		/* --foo long option */
+		else if (*place != ':' && strchr(options, *place) != NULL)
+			short_too = 1;		/* could be short option too */
+
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, short_too);
+		if (optchar != -1) {
+			place = EMSG;
+			return (optchar);
+		}
+	}
+
+	if ((optchar = (int)*place++) == (int)':' ||
+	    (optchar == (int)'-' && *place != '\0') ||
+	    (oli = strchr(options, optchar)) == NULL) {
+		/*
+		 * If the user specified "-" and  '-' isn't listed in
+		 * options, return -1 (non-option) as per POSIX.
+		 * Otherwise, it is an unknown option character (or ':').
+		 */
+		if (optchar == (int)'-' && *place == '\0')
+			return (-1);
+		if (!*place)
+			++optind;
+		if (PRINT_ERROR)
+			warnx(illoptchar, optchar);
+		optopt = optchar;
+		return (BADCH);
+	}
+	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+		/* -W long-option */
+		if (*place)			/* no space */
+			/* NOTHING */;
+		else if (++optind >= nargc) {	/* no arg */
+			place = EMSG;
+			if (PRINT_ERROR)
+				warnx(recargchar, optchar);
+			optopt = optchar;
+			return (BADARG);
+		} else				/* white space */
+			place = nargv[optind];
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, 0);
+		place = EMSG;
+		return (optchar);
+	}
+	if (*++oli != ':') {			/* doesn't take argument */
+		if (!*place)
+			++optind;
+	} else {				/* takes (optional) argument */
+		optarg = NULL;
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (oli[1] != ':') {	/* arg not optional */
+			if (++optind >= nargc) {	/* no arg */
+				place = EMSG;
+				if (PRINT_ERROR)
+					warnx(recargchar, optchar);
+				optopt = optchar;
+				return (BADARG);
+			} else
+				optarg = nargv[optind];
+		}
+		place = EMSG;
+		++optind;
+	}
+	/* dump back option letter */
+	return (optchar);
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+	/*
+	 * We don't pass FLAG_PERMUTE to getopt_internal() since
+	 * the BSD getopt(3) (unlike GNU) has never done this.
+	 *
+	 * Furthermore, since many privileged programs call getopt()
+	 * before dropping privileges it makes sense to keep things
+	 * as simple (and bug-free) as possible.
+	 */
+	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+/*
+ * getopt_long --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE|FLAG_LONGONLY));
+}

+ 105 - 0
src/apps/common/win/getopt.h

@@ -0,0 +1,105 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is a part of the w64 mingw-runtime package.
+ *
+ * The w64 mingw-runtime package and its code is distributed in the hope that it 
+ * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR 
+ * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to 
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include <crtdefs.h>
+
+#if defined( WINGETOPT_SHARED_LIB )
+# if defined( BUILDING_WINGETOPT_DLL )
+#  define WINGETOPT_API __declspec(dllexport)
+# else
+#  define WINGETOPT_API __declspec(dllimport)
+# endif
+#else
+# define WINGETOPT_API
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WINGETOPT_API extern int optind;		/* index of first non-option in argv      */
+WINGETOPT_API extern int optopt;		/* single option character, as parsed     */
+WINGETOPT_API extern int opterr;		/* flag to enable built-in diagnostics... */
+				/* (user may set to zero, to suppress)    */
+
+WINGETOPT_API extern char *optarg;		/* pointer to argument of current option  */
+
+extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing.  We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset  __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header.  However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner.  Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#endif /* !defined(__GETOPT_H__) */
+
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option		/* specification for a long form option...	*/
+{
+  const char *name;		/* option name, without leading hyphens */
+  int         has_arg;		/* does it take an argument?		*/
+  int        *flag;		/* where to save its status, or NULL	*/
+  int         val;		/* its associated status value		*/
+};
+
+enum    		/* permitted values for its `has_arg' field...	*/
+{
+  no_argument = 0,      	/* option never takes an argument	*/
+  required_argument,		/* option always requires an argument	*/
+  optional_argument		/* option may take an argument		*/
+};
+
+extern int getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx);
+extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT	1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */

+ 9 - 1
src/apps/natdiscovery/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnutils_natdiscovery)
 
@@ -8,7 +8,15 @@ set(SOURCE_FILES
 
 add_executable(${PROJECT_NAME} ${SOURCE_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turnclient)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+   )
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )

+ 6 - 1
src/apps/natdiscovery/natdiscovery.c

@@ -28,12 +28,16 @@
 * SUCH DAMAGE.
 */
 
-#include <err.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
+#if defined(WINDOWS)
+#include <getopt.h>
+#else
 #include <unistd.h>
+#include <err.h>
+#endif
 
 #include "ns_turn_utils.h"
 #include "apputils.h"
@@ -627,6 +631,7 @@ int main(int argc, char **argv)
 	int first=1;
 	ioa_addr other_addr, reflexive_addr, tmp_addr, remote_addr, local_addr, local2_addr;
 
+	if (socket_init()) return -1;
 
 	set_logfile("stdout");
 	set_system_parameters(0);

+ 9 - 1
src/apps/oauth/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnutils_oauth)
 
@@ -8,7 +8,15 @@ set(SOURCE_FILES
 
 add_executable(${PROJECT_NAME} ${SOURCE_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turnclient)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    )
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )

+ 4 - 1
src/apps/oauth/oauth.c

@@ -28,11 +28,14 @@
  * SUCH DAMAGE.
  */
 
+#if defined(__unix__)
+#include <unistd.h>
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
 #include <getopt.h>
 #include <stddef.h>
 

+ 9 - 1
src/apps/peer/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnutils_peer)
 
@@ -8,7 +8,15 @@ set(SOURCE_FILES
 
 add_executable(${PROJECT_NAME} ${SOURCE_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turnclient)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    )
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )

+ 6 - 0
src/apps/peer/mainudpserver.c

@@ -36,7 +36,11 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
+#if defined(_MSC_VER)
+#include <getopt.h>
+#else
 #include <unistd.h>
+#endif
 
 //////////////// local definitions /////////////////
 
@@ -60,6 +64,8 @@ int main(int argc, char **argv)
 	int c;
 	char ifname[1025] = "\0";
 
+	if (socket_init()) return -1;
+
 	IS_TURN_SERVER = 1;
 
 	set_logfile("stdout");

+ 2 - 2
src/apps/peer/udpserver.c

@@ -63,7 +63,7 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg)
 static int udp_create_server_socket(server_type* server, 
 				    const char* ifname, const char *local_address, int port) {
 
-  FUNCSTART;
+  if(server && server->verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Start\n");
 
   if(!server) return -1;
 
@@ -96,7 +96,7 @@ static int udp_create_server_socket(server_type* server,
   
   event_add(udp_ev,NULL);
   
-  FUNCEND;
+  if(server && server->verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "End\n");
   
   return 0;
 }

+ 0 - 5
src/apps/peer/udpserver.h

@@ -46,11 +46,6 @@ extern "C" {
 struct server_info;
 typedef struct server_info server_type;
 
-///////////////////////////////////////////////////
-
-#define FUNCSTART if(server && server->verbose) turn_log_func_default(TURN_LOG_LEVEL_INFO,"%s:%d:start\n",__FUNCTION__,__LINE__)
-#define FUNCEND if(server && server->verbose) turn_log_func_default(TURN_LOG_LEVEL_INFO,"%s:%d:end\n",__FUNCTION__,__LINE__)
-
 ///////////////////////////////////////////////////////
 
 struct server_info {

+ 68 - 23
src/apps/relay/CMakeLists.txt

@@ -1,8 +1,17 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnserver)
 
-set(HEAD_FILES
+check_function_exists("pthread_barrier_init" HAVE_THREAD_BARRIERS)
+if(NOT HAVE_THREAD_BARRIERS)
+    list(APPEND turnserver_DEFINED TURN_NO_THREAD_BARRIERS)
+endif()
+
+if(MSVC OR MINGW)
+    list(APPEND turnserver_LIBS Iphlpapi)
+endif()
+
+set(HEADER_FILES
     tls_listener.h
     mainrelay.h
     turn_admin_server.h
@@ -34,7 +43,7 @@ find_package(SQLite)
 if(SQLite_FOUND)
     list(APPEND turnserver_LIBS SQLite::sqlite)
     list(APPEND SOURCE_FILES dbdrivers/dbd_sqlite.c)
-    list(APPEND HEAD_FILES dbdrivers/dbd_sqlite.h)
+    list(APPEND HEADER_FILES dbdrivers/dbd_sqlite.h)
 else()
     list(APPEND turnserver_DEFINED TURN_NO_SQLITE)
 endif()
@@ -43,42 +52,57 @@ find_package(PostgreSQL)
 if(PostgreSQL_FOUND)
     list(APPEND turnserver_LIBS PostgreSQL::pq)
     list(APPEND SOURCE_FILES dbdrivers/dbd_pgsql.c)
-    list(APPEND HEAD_FILES dbdrivers/dbd_pgsql.h)
+    list(APPEND HEADER_FILES dbdrivers/dbd_pgsql.h)
 else()
     list(APPEND turnserver_DEFINED TURN_NO_PQ)
 endif()
 
-find_package(MySQL)
-if(MySQL_FOUND)
+option(WITH_MYSQL "Use mysql" ON)
+if(WITH_MYSQL)
+    find_package(MySQL)
+    if(MySQL_FOUND)
     list(APPEND turnserver_LIBS MySQL::mysql)
     list(APPEND SOURCE_FILES dbdrivers/dbd_mysql.c)
-    list(APPEND HEAD_FILES dbdrivers/dbd_mysql.h)
+      list(APPEND HEADER_FILES dbdrivers/dbd_mysql.h)
+    else()
+        list(APPEND turnserver_DEFINED TURN_NO_MYSQL)
+    endif()
 else()
     list(APPEND turnserver_DEFINED TURN_NO_MYSQL)
 endif()
 
-find_package(mongo)
-if(mongo_FOUND)
-    list(APPEND turnserver_LIBS mongo)
+if(WIN32)
+	find_package(mongoc-1.0)
+	if(mongoc-1.0_FOUND)
+		list(APPEND turnserver_LIBS mongo::mongoc_shared)
     list(APPEND SOURCE_FILES dbdrivers/dbd_mongo.c)
-    list(APPEND HEAD_FILES dbdrivers/dbd_mongo.h)
+		list(APPEND HEADER_FILES dbdrivers/dbd_mongo.h)
+	else()
+		list(APPEND turnserver_DEFINED TURN_NO_MONGO)
+	endif()
 else()
+	find_package(mongo)
+	if(mongo_FOUND)
+    list(APPEND turnserver_LIBS mongo)
+    list(APPEND SOURCE_FILES dbdrivers/dbd_mongo.c)
+		list(APPEND HEADER_FILES dbdrivers/dbd_mongo.h)
+	else()
     list(APPEND turnserver_DEFINED TURN_NO_MONGO)
+	endif()
 endif()
 
 find_package(hiredis)
 if(hiredis_FOUND)
     list(APPEND turnserver_LIBS hiredis::hiredis)
     list(APPEND SOURCE_FILES dbdrivers/dbd_redis.c)
-    list(APPEND HEAD_FILES dbdrivers/dbd_redis.h)
+    list(APPEND HEADER_FILES dbdrivers/dbd_redis.h)
 else()
     list(APPEND turnserver_DEFINED TURN_NO_HIREDIS)
 endif()
 
-if(NOT APPLE)
+if(UNIX)
     find_package(libsystemd)
-    if(libsystemd_FOUND)
-    else()
+    if(NOT libsystemd_FOUND)
         list(APPEND turnserver_DEFINED TURN_NO_SYSTEMD)
     endif()
 else()
@@ -88,28 +112,49 @@ endif()
 find_package(Prometheus)
 if(Prometheus_FOUND)
     list(APPEND SOURCE_FILES prom_server.c)
-    list(APPEND HEAD_FILES prom_server.h)
+    list(APPEND HEADER_FILES prom_server.h)
 else()
     list(APPEND turnserver_DEFINED TURN_NO_PROMETHEUS)
 endif()
 
 list(APPEND turnserver_DEFINED TURN_NO_SCTP)
 
-add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEAD_FILES})
+message("turnserver_LIBS:${turnserver_LIBS}")
+
+add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turn_server ${turnserver_LIBS})
 target_include_directories(${PROJECT_NAME} PRIVATE ${turnserver_include_dirs})
 target_compile_definitions(${PROJECT_NAME} PRIVATE ${turnserver_DEFINED})
-
-add_custom_target(turnadmin ALL
-    COMMAND 
-        ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE_NAME:${PROJECT_NAME}> turnadmin
-    DEPENDS ${PROJECT_NAME})
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    )
 
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
 
-INSTALL(FILES $<TARGET_FILE_DIR:${PROJECT_NAME}>/turnadmin
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )
+
+if(WIN32)
+    add_custom_target(turnadmin ALL
+        COMMAND
+            ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}>/turnadmin.exe
+        DEPENDS ${PROJECT_NAME})
+    INSTALL(FILES $<TARGET_FILE_DIR:${PROJECT_NAME}>/turnadmin.exe
     DESTINATION "${CMAKE_INSTALL_BINDIR}"
             COMPONENT Runtime)
+else()
+    add_custom_target(turnadmin ALL
+        COMMAND
+            ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}>/turnadmin
+        DEPENDS ${PROJECT_NAME})
+    INSTALL(FILES $<TARGET_FILE_DIR:${PROJECT_NAME}>/turnadmin
+        DESTINATION "${CMAKE_INSTALL_BINDIR}"
+            COMPONENT Runtime
+		)
+endif()

+ 33 - 2
src/apps/relay/dbdrivers/dbd_sqlite.c

@@ -36,8 +36,12 @@
 
 #include <sqlite3.h>
 
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+    || defined(__DARWIN__) || defined(__MACH__)
 #include <unistd.h>
+#include <sys/types.h>
 #include <pwd.h>
+#endif
 
 #include <pthread.h>
 
@@ -48,7 +52,11 @@ static pthread_cond_t rc_cond = PTHREAD_COND_INITIALIZER;
 
 static int read_threads = 0;
 static int write_level = 0;
+#if defined(WINDOWS)
+static pthread_t write_thread = {0};
+#else
 static pthread_t write_thread = 0;
+#endif
 
 static void sqlite_lock(int write)
 {
@@ -57,14 +65,29 @@ static void sqlite_lock(int write)
 	int can_move = 0;
 	while (!can_move) {
 		pthread_mutex_lock(&rc_mutex);
+#if defined(WINDOWS)
+		pthread_t zero = { 0 };
+#endif
 		if (write) {
-			if (((write_thread == 0) && (read_threads < 1)) || (write_thread == pths)) {
+			if ((
+#if defined(WINDOWS)
+				pthread_equal(write_thread, zero)
+#else
+				write_thread == 0
+#endif
+				&& (read_threads < 1)) || pthread_equal(write_thread, pths)) {
 				can_move = 1;
 				++write_level;
 				write_thread = pths;
 			}
 		} else {
-			if ((!write_thread) || (write_thread == pths)) {
+			if ((
+#if defined(WINDOWS)
+				pthread_equal(write_thread, zero))
+#else
+				!write_thread)
+#endif
+				|| pthread_equal(write_thread, pths)) {
 				can_move = 1;
 				++read_threads;
 			}
@@ -81,7 +104,12 @@ static void sqlite_unlock(int write)
 	pthread_mutex_lock(&rc_mutex);
 	if (write) {
 		if (!(--write_level)) {
+#if defined(WINDOWS)
+			pthread_t zero = { 0 };
+			write_thread = zero;
+#else
 			write_thread = 0;
+#endif
 			pthread_cond_broadcast(&rc_cond);
 		}
 	} else {
@@ -121,6 +149,8 @@ static int donot_print_connection_success = 0;
 static void fix_user_directory(char *dir0) {
 	char *dir = dir0;
 	while(*dir == ' ') ++dir;
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+    || defined(__DARWIN__) || defined(__MACH__)
 	if(*dir == '~') {
 		char *home=getenv("HOME");
 		if(!home) {
@@ -143,6 +173,7 @@ static void fix_user_directory(char *dir0) {
 		strncpy(dir0,dir_fixed,sz);
 		free(dir_fixed);
 	}
+#endif
 }
 
 static void init_sqlite_database(sqlite3 *sqliteconnection) {

+ 37 - 13
src/apps/relay/dtls_listener.c

@@ -41,6 +41,11 @@
 /* #define REQUEST_CLIENT_CERT */
 
 ///////////////////////////////////////////////////
+#if defined(WINDOWS)
+    //TODO: test it!
+    /* Type to represent a port.  */
+    typedef uint16_t in_port_t;
+#endif
 
 #define FUNCSTART if(server && eve(server->verbose)) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s:%d:start\n",__FUNCTION__,__LINE__)
 #define FUNCEND if(server && eve(server->verbose)) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s:%d:end\n",__FUNCTION__,__LINE__)
@@ -390,15 +395,20 @@ static int handle_udp_packet(dtls_listener_relay_server_type *server,
 			{
 				uint8_t saddr[129];
 				uint8_t rsaddr[129];
-				long thrid = (long) pthread_self();
 				addr_to_string(get_local_addr_from_ioa_socket(chs),saddr);
 				addr_to_string(get_remote_addr_from_ioa_socket(chs),rsaddr);
+				long thrid = 0;
+#ifdef WINDOWS
+				thrid = GetCurrentThreadId();
+#else
+				thrid = (long)pthread_self();
+#endif
 				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
 					"%s: 111.111: thrid=0x%lx: Amap = 0x%lx, socket container=0x%lx, local addr %s, remote addr %s, s=0x%lx, done=%d, tbc=%d\n",
-					__FUNCTION__, thrid, (long) amap,
-					(long) (chs->sockets_container), (char*) saddr,
-					(char*) rsaddr, (long) s, (int) (chs->done),
-					(int) (chs->tobeclosed));
+					__FUNCTION__, thrid, (long)amap,
+					(long)(chs->sockets_container), (char*)saddr,
+					(char*)rsaddr, (long)s, (int)(chs->done),
+					(int)(chs->tobeclosed));
 			}
 		}
 
@@ -413,16 +423,22 @@ static int handle_udp_packet(dtls_listener_relay_server_type *server,
 			{
 				uint8_t saddr[129];
 				uint8_t rsaddr[129];
-				long thrid = (long) pthread_self();
+
 				addr_to_string(get_local_addr_from_ioa_socket(chs),saddr);
 				addr_to_string(get_remote_addr_from_ioa_socket(chs),rsaddr);
+				long thrid = 0;
+#ifdef WINDOWS
+				thrid = GetCurrentThreadId();
+#else
+				thrid = (long)pthread_self();
+#endif
 				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
 					"%s: 111.222: thrid=0x%lx: Amap = 0x%lx, socket container=0x%lx, local addr %s, remote addr %s, s=0x%lx, done=%d, tbc=%d, st=%d, sat=%d\n",
-					__FUNCTION__, thrid, (long) amap,
-					(long) (chs->sockets_container), (char*) saddr,
-					(char*) rsaddr, (long) chs, (int) (chs->done),
-					(int) (chs->tobeclosed), (int) (chs->st),
-					(int) (chs->sat));
+					__FUNCTION__, thrid, (long)amap,
+					(long)(chs->sockets_container), (char*)saddr,
+					(char*)rsaddr, (long)chs, (int)(chs->done),
+					(int)(chs->tobeclosed), (int)(chs->st),
+					(int)(chs->sat));
 			}
 		}
 
@@ -643,9 +659,12 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg)
 	addr_set_any(&(server->sm.m.sm.nd.src_addr));
 
 	ssize_t bsize = 0;
-
+#if defined(WINDOWS)
+	//TODO: implement it!!!
+	int flags = 0;
+#else
 	int flags = MSG_DONTWAIT;
-
+#endif
 	bsize = udp_recvfrom(fd, &(server->sm.m.sm.nd.src_addr), &(server->addr),
 			(char*)ioa_network_buffer_data(elem), (int)ioa_network_buffer_get_capacity_udp(),
 			&(server->sm.m.sm.nd.recv_ttl), &(server->sm.m.sm.nd.recv_tos),
@@ -665,8 +684,13 @@ static void udp_server_input_handler(evutil_socket_t fd, short what, void* arg)
 
 	#if defined(MSG_ERRQUEUE)
 
+#if defined(WINDOWS)
+		//TODO: implement it!!!
+		int eflags = MSG_ERRQUEUE;
+#else
 		//Linux
 		int eflags = MSG_ERRQUEUE | MSG_DONTWAIT;
+#endif
 		static char buffer[65535];
 		uint32_t errcode = 0;
 		ioa_addr orig_addr;

+ 7 - 12
src/apps/relay/http_server.c

@@ -110,8 +110,7 @@ static struct headers_list * post_parse(char *data, size_t data_len)
 			memcpy(post_data, data, data_len);
 			char *fmarker = NULL;
 			char *fsplit = strtok_r(post_data, "&", &fmarker);
-			struct headers_list *list = (struct headers_list*)malloc(sizeof(struct headers_list));
-			memset(list,0,sizeof(struct headers_list));
+			struct headers_list *list = (struct headers_list*)calloc(sizeof(struct headers_list), 1);
 			while (fsplit != NULL) {
 				char *vmarker = NULL;
 				char *key = strtok_r(fsplit, "=", &vmarker);
@@ -164,14 +163,12 @@ static struct http_request* parse_http_request_1(struct http_request* ret, char*
 
 				const char *query = evhttp_uri_get_query(uri);
 				if(query) {
-					struct evkeyvalq* kv = (struct evkeyvalq*)malloc(sizeof(struct evkeyvalq));
-					memset(kv,0,sizeof(struct evkeyvalq));
+					struct evkeyvalq* kv = (struct evkeyvalq*)calloc(sizeof(struct evkeyvalq), 1);
 					if(evhttp_parse_query_str(query, kv)<0) {
 						free(ret);
 						ret = NULL;
 					} else {
-						ret->headers = (struct http_headers*)malloc(sizeof(struct http_headers));
-						memset(ret->headers,0,sizeof(struct http_headers));
+						ret->headers = (struct http_headers*)calloc(sizeof(struct http_headers), 1);
 						ret->headers->uri_headers = kv;
 					}
 				}
@@ -186,8 +183,7 @@ static struct http_request* parse_http_request_1(struct http_request* ret, char*
 					char *body = strstr(s+1,"\r\n\r\n");
 					if(body && body[0]) {
 						if(!ret->headers) {
-							ret->headers = (struct http_headers*)malloc(sizeof(struct http_headers));
-							memset(ret->headers,0,sizeof(struct http_headers));
+							ret->headers = (struct http_headers*)calloc(sizeof(struct http_headers), 1);
 						}
 						ret->headers->post_headers = post_parse(body,strlen(body));
 					}
@@ -207,8 +203,7 @@ struct http_request* parse_http_request(char* request) {
 
 	if(request) {
 
-		ret = (struct http_request*)malloc(sizeof(struct http_request));
-		memset(ret,0,sizeof(struct http_request));
+		ret = (struct http_request*)calloc(sizeof(struct http_request), 1);
 
 		if(strstr(request,"GET ") == request) {
 			ret->rtype = HRT_GET;
@@ -326,8 +321,8 @@ struct str_buffer {
 
 struct str_buffer* str_buffer_new(void)
 {
-	struct str_buffer* ret = (struct str_buffer*)malloc(sizeof(struct str_buffer));
-	memset(ret,0,sizeof(struct str_buffer));
+	struct str_buffer* ret = (struct str_buffer*)calloc(sizeof(struct str_buffer), 1);
+
 	ret->buffer = (char*)malloc(1);
 	ret->buffer[0] = 0;
 	ret->capacity = 1;

+ 30 - 30
src/apps/relay/libtelnet.c

@@ -21,7 +21,7 @@
 #include <stdarg.h>
 
 /* Win32 compatibility */
-#if defined(_WIN32)
+#if defined(WINDOWS)
 # define vsnprintf _vsnprintf
 # define __func__ __FUNCTION__
 # define ZLIB_WINAPI 1
@@ -134,7 +134,7 @@ static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) /
 #define Q_BUFFER_GROWTH_QUANTUM 4
 
 /* error generation function */
-static telnet_error_t _error(telnet_t *telnet, unsigned line,
+static telnet_error_t telnet_error(telnet_t *telnet, unsigned line,
 		const char* func, telnet_error_t err, int fatal, const char *fmt,
 		...) {
 	telnet_event_t ev;
@@ -169,26 +169,26 @@ telnet_error_t _init_zlib(telnet_t *telnet, int deflate, int err_fatal) {
 
 	/* if compression is already enabled, fail loudly */
 	if (telnet->z != 0)
-		return _error(telnet, __LINE__, __func__, TELNET_EBADVAL,
+		return telnet_error(telnet, __LINE__, __func__, TELNET_EBADVAL,
 				err_fatal, "cannot initialize compression twice");
 
 	/* allocate zstream box */
 	if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0)
-		return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal,
+		return telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal,
 				"malloc() failed: %s", strerror(errno));
 
 	/* initialize */
 	if (deflate) {
 		if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) {
 			free(z);
-			return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
+			return telnet_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
 					err_fatal, "deflateInit() failed: %s", zError(rs));
 		}
 		telnet->flags |= TELNET_PFLAG_DEFLATE;
 	} else {
 		if ((rs = inflateInit(z)) != Z_OK) {
 			free(z);
-			return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
+			return telnet_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS,
 					err_fatal, "inflateInit() failed: %s", zError(rs));
 		}
 		telnet->flags &= ~TELNET_PFLAG_DEFLATE;
@@ -221,7 +221,7 @@ static void _send(telnet_t *telnet, const char *buffer,
 		while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) {
 			/* compress */
 			if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) {
-				_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
+				telnet_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
 						"deflate() failed: %s", zError(rs));
 				deflateEnd(telnet->z);
 				free(telnet->z);
@@ -336,7 +336,7 @@ static INLINE void _set_rfc1143(telnet_t *telnet, unsigned char telopt,
 		if ((qtmp = (telnet_rfc1143_t *)realloc(telnet->q,
 			sizeof(telnet_rfc1143_t) *
             	(telnet->q_size + Q_BUFFER_GROWTH_QUANTUM))) == 0) {
-			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 					"realloc() failed: %s", strerror(errno));
 			return;
 		}
@@ -404,13 +404,13 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) {
 		case Q_WANTNO:
 			_set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 			NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
-			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 					"DONT answered by WILL");
 			break;
 		case Q_WANTNO_OP:
 			_set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 			NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
-			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 					"DONT answered by WILL");
 			break;
 		case Q_WANTYES:
@@ -462,13 +462,13 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) {
 		case Q_WANTNO:
 			_set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 			NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
-			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 					"WONT answered by DO");
 			break;
 		case Q_WANTNO_OP:
 			_set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 			NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
-			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 					"WONT answered by DO");
 			break;
 		case Q_WANTYES:
@@ -537,7 +537,7 @@ static int _environ_telnet(telnet_t *telnet, unsigned char type,
 	if ((unsigned)buffer[0] != TELNET_ENVIRON_SEND &&
 			(unsigned)buffer[0] != TELNET_ENVIRON_IS &&
 			(unsigned)buffer[0] != TELNET_ENVIRON_INFO) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"telopt %d subneg has invalid command", type);
 		return 0;
 	}
@@ -561,14 +561,14 @@ static int _environ_telnet(telnet_t *telnet, unsigned char type,
 	/* very second byte must be VAR or USERVAR, if present */
 	if ((unsigned)buffer[1] != TELNET_ENVIRON_VAR &&
 			(unsigned)buffer[1] != TELNET_ENVIRON_USERVAR) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"telopt %d subneg missing variable type", type);
 		return 0;
 	}
 
 	/* ensure last byte is not an escape byte (makes parsing later easier) */
 	if ((unsigned)buffer[size - 1] == TELNET_ENVIRON_ESC) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"telopt %d subneg ends with ESC", type);
 		return 0;
 	}
@@ -587,7 +587,7 @@ static int _environ_telnet(telnet_t *telnet, unsigned char type,
 	/* allocate argument array, bail on error */
 	if ((values = (struct telnet_environ_t *)calloc(count,
 			sizeof(struct telnet_environ_t))) == 0) {
-		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 				"calloc() failed: %s", strerror(errno));
 		return 0;
 	}
@@ -678,7 +678,7 @@ static int _mssp_telnet(telnet_t *telnet, char* buffer, size_t size) {
 
 	/* first byte must be a VAR */
 	if ((unsigned)buffer[0] != TELNET_MSSP_VAR) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"MSSP subnegotiation has invalid data");
 		return 0;
 	}
@@ -693,7 +693,7 @@ static int _mssp_telnet(telnet_t *telnet, char* buffer, size_t size) {
 	/* allocate argument array, bail on error */
 	if ((values = (struct telnet_environ_t *)calloc(count,
 			sizeof(struct telnet_environ_t))) == 0) {
-		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 				"calloc() failed: %s", strerror(errno));
 		return 0;
 	}
@@ -720,7 +720,7 @@ static int _mssp_telnet(telnet_t *telnet, char* buffer, size_t size) {
 			values[i].value = last;
 			++i;
 		} else {
-			_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 					"invalid MSSP subnegotiation data");
 			free(values);
 			return 0;
@@ -750,7 +750,7 @@ static int _zmp_telnet(telnet_t *telnet, const char* buffer, size_t size) {
 
 	/* make sure this is a valid ZMP buffer */
 	if (size == 0 || buffer[size - 1] != 0) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"incomplete ZMP frame");
 		return 0;
 	}
@@ -761,7 +761,7 @@ static int _zmp_telnet(telnet_t *telnet, const char* buffer, size_t size) {
 
 	/* allocate argument array, bail on error */
 	if ((argv = (const char **)calloc(argc, sizeof(const char *))) == 0) {
-		_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 				"calloc() failed: %s", strerror(errno));
 		return 0;
 	}
@@ -789,7 +789,7 @@ static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
 
 	/* make sure request is not empty */
 	if (size == 0) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"incomplete TERMINAL-TYPE request");
 		return 0;
 	}
@@ -797,7 +797,7 @@ static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
 	/* make sure request has valid command type */
 	if (buffer[0] != TELNET_TTYPE_IS &&
 			buffer[0] != TELNET_TTYPE_SEND) {
-		_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+		telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 				"TERMINAL-TYPE request has invalid type");
 		return 0;
 	}
@@ -808,7 +808,7 @@ static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
 
 		/* allocate space for name */
 		if ((name = (char *)malloc(size)) == 0) {
-			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 					"malloc() failed: %s", strerror(errno));
 			return 0;
 		}
@@ -948,7 +948,7 @@ static telnet_error_t _buffer_byte(telnet_t *telnet,
 
 		/* overflow -- can't grow any more */
 		if (i >= _buffer_sizes_count - 1) {
-			_error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
 					"subnegotiation buffer size limit reached");
 			return TELNET_EOVERFLOW;
 		}
@@ -956,7 +956,7 @@ static telnet_error_t _buffer_byte(telnet_t *telnet,
 		/* (re)allocate buffer */
 		new_buffer = (char *)realloc(telnet->buffer, _buffer_sizes[i + 1]);
 		if (new_buffer == 0) {
-			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 					"realloc() failed");
 			return TELNET_ENOMEM;
 		}
@@ -1141,7 +1141,7 @@ static void _process(telnet_t *telnet, const char *buffer, size_t size) {
 			 * given command as an IAC code.
 			 */
 			default:
-				_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
+				telnet_error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 						"unexpected byte after IAC inside SB: %d",
 						byte);
 
@@ -1204,7 +1204,7 @@ void telnet_recv(telnet_t *telnet, const char *buffer,
 				_process(telnet, inflate_buffer, sizeof(inflate_buffer) -
 						telnet->z->avail_out);
 			else
-				_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
+				telnet_error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1,
 						"inflate() failed: %s", zError(rs));
 
 			/* prepare output buffer for next run */
@@ -1481,7 +1481,7 @@ int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
 	if (rs >= sizeof(buffer)) {
 		output = (char*)malloc(rs + 1);
 		if (output == 0) {
-			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 					"malloc() failed: %s", strerror(errno));
 			va_end(va2);
 			return -1;
@@ -1550,7 +1550,7 @@ int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
 	if (rs >= sizeof(buffer)) {
 		output = (char*)malloc(rs + 1);
 		if (output == 0) {
-			_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
+			telnet_error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 					"malloc() failed: %s", strerror(errno));
 			va_end(va2);
 			return -1;

+ 627 - 116
src/apps/relay/mainrelay.c

@@ -35,6 +35,15 @@
 #include "prom_server.h"
 #endif
 
+#if defined(WINDOWS)
+    #include <Iphlpapi.h>
+
+    #define WORKING_BUFFER_SIZE 15000
+    #define MAX_TRIES 3
+
+    #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+    #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+#endif
 
 #if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
 #undef OPENSSL_VERSION_NUMBER
@@ -83,102 +92,155 @@ char HTTP_ALPN[128] = "http/1.1";
 #define DEFAULT_GENERAL_RELAY_SERVERS_NUMBER (1)
 
 turn_params_t turn_params = {
-NULL, /* tls_ctx */
-NULL, /* dtls_ctx */
-DH_2066, "", "", "",
-"turn_server_cert.pem","turn_server_pkey.pem", "", "",
-0,0,0,
-#if !TLS_SUPPORTED
+    //////////////// OpenSSL group //////////////////////
+    NULL, /* tls_ctx */
+    NULL, /* dtls_ctx */
+    DH_2066, /*dh_key_size*/
+	
+	"", /*cipher_list*/
+	"", /*ec_curve_name*/
+	
+	"", /*ca_cert_file*/
+    "turn_server_cert.pem", /*cert_file*/
+	"turn_server_pkey.pem", /*pkey_file*/
+	"", /*tls_password*/
+	"", /*dh_file*/
+
+    0, /*no_tlsv1*/
+	0, /*no_tlsv1_1*/
+	0, /*no_tlsv1_2*/
+	/*no_tls*/
+    #if !TLS_SUPPORTED
 	1,
-#else
+    #else
 	0,
-#endif
-
-#if !DTLS_SUPPORTED
+    #endif
+	/*no_dtls*/
+    #if !DTLS_SUPPORTED
 	1,
-#else
+    #else
 	0,
-#endif
+    #endif
 
-NULL, PTHREAD_MUTEX_INITIALIZER,
+    NULL, /*tls_ctx_update_ev*/
+    {0, NULL}, /*tls_mutex*/
 
-//////////////// Common params ////////////////////
+    //////////////// Common params ////////////////////
 	TURN_VERBOSE_NONE, /* verbose */
 	0, /* turn_daemon */
 	0, /* no_software_attribute */
 	0, /* web_admin_listen_on_workers */
+
 	0, /* do_not_use_config_file */
-"/var/run/turnserver.pid", /* pidfile */
-"", /* acme_redirect */
-DEFAULT_STUN_PORT, /* listener_port*/
-DEFAULT_STUN_TLS_PORT, /* tls_listener_port */
-0, /* alt_listener_port */
-0, /* alt_tls_listener_port */
-0, /* tcp_proxy_port */
-1, /* rfc5780 */
-0, /* no_udp */
-0, /* no_tcp */
-0, /* tcp_use_proxy */
-0, /* no_tcp_relay */
-0, /* no_udp_relay */
-"",
-{"",""},0,
-{
-  NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,NULL,NULL,NULL
-},
-{NULL, 0},{NULL, 0},
-NEV_UNKNOWN,
-{ "Unknown", "UDP listening socket per session", "UDP thread per network endpoint", "UDP thread per CPU core" },
-//////////////// Relay servers //////////////////////////////////
-LOW_DEFAULT_PORTS_BOUNDARY,HIGH_DEFAULT_PORTS_BOUNDARY,0,0,0,"",
-0,NULL,0,NULL,DEFAULT_GENERAL_RELAY_SERVERS_NUMBER,0,
-////////////// Auth server /////////////////////////////////////
-"","",0,
-/////////////// AUX SERVERS ////////////////
-{NULL,0,{0,NULL}},0,
-/////////////// ALTERNATE SERVERS ////////////////
-{NULL,0,{0,NULL}},{NULL,0,{0,NULL}},
-/////////////// stop server ////////////////
-0,
-/////////////// MISC PARAMS ////////////////
-0, /* stun_only */
-0, /* no_stun */
-0, /* secure_stun */
-0, /* server_relay */
-0, /* fingerprint */
-':', /* rest_api_separator */
-STUN_DEFAULT_NONCE_EXPIRATION_TIME, /* stale_nonce */
-STUN_DEFAULT_MAX_ALLOCATE_LIFETIME, /* max_allocate_lifetime */
-STUN_DEFAULT_CHANNEL_LIFETIME, /* channel_lifetime */
-STUN_DEFAULT_PERMISSION_LIFETIME, /* permission_lifetime */
-0, /* mobility */
-TURN_CREDENTIALS_NONE, /* ct */
-0, /* use_auth_secret_with_timestamp */
-0, /* max_bps */
-0, /* bps_capacity */
-0, /* bps_capacity_allocated */
-0, /* total_quota */
-0, /* user_quota */
-#if !defined(TURN_NO_PROMETHEUS)
-0, /* prometheus disabled by default */
-DEFAULT_PROM_SERVER_PORT, /* prometheus port */
-0, /* prometheus username labelling disabled by default when prometheus is enabled */
-#endif
-///////////// Users DB //////////////
-{ (TURN_USERDB_TYPE)0, {"\0","\0"}, {0,NULL, {NULL,0}} },
-///////////// CPUs //////////////////
-DEFAULT_CPUS_NUMBER,
-///////// Encryption /////////
-"", /* secret_key_file */
-"", /* secret_key */
-ALLOCATION_DEFAULT_ADDRESS_FAMILY_IPV4,  /* allocation_default_address_family */
-0,  /* no_auth_pings */
-0,  /* no_dynamic_ip_list */
-0,  /* no_dynamic_realms */
-
-0,  /* log_binding */
-0,	/* no_stun_backward_compatibility */
-0	/* response_origin_only_with_rfc5780 */
+
+    "/var/run/turnserver.pid", /* pidfile */
+    "", /* acme_redirect */
+
+    ////////////////  Listener server /////////////////
+
+    DEFAULT_STUN_PORT, /* listener_port*/
+    DEFAULT_STUN_TLS_PORT, /* tls_listener_port */
+    0, /* alt_listener_port */
+    0, /* alt_tls_listener_port */
+    0, /* tcp_proxy_port */
+    1, /* rfc5780 */
+
+    0, /* no_udp */
+    0, /* no_tcp */
+    0, /* tcp_use_proxy */
+
+    0, /* no_tcp_relay */
+    0, /* no_udp_relay */
+
+    "", /*listener_ifname*/
+
+    {"", ""}, /*redis_statsdb*/
+    0, /*use_redis_statsdb*/
+    {
+        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,NULL,NULL,NULL
+    }, /*listener*/
+    {NULL, 0}, /*ip_whitelist*/
+    {NULL, 0}, /*ip_blacklist*/
+    NEV_UNKNOWN, /*net_engine_version*/
+    { "Unknown",
+	"UDP listening socket per session",
+	"UDP thread per network endpoint",
+	"UDP thread per CPU core" }, /*net_engine_version_txt*/
+
+    //////////////// Relay servers //////////////////////////////////
+    LOW_DEFAULT_PORTS_BOUNDARY, /*min_port*/
+    HIGH_DEFAULT_PORTS_BOUNDARY,/*max_port*/
+
+    0, /*check_origin*/
+
+    0, /*no_multicast_peers*/
+    0, /*allow_loopback_peers*/
+
+    "", /*relay_ifname*/
+    0, /*relays_number*/
+    NULL, /*relay_addrs*/
+    0, /*default_relays*/
+
+    NULL, /*external_ip*/
+    DEFAULT_GENERAL_RELAY_SERVERS_NUMBER, /*general_relay_servers_number*/
+    0, /*udp_relay_servers_number*/
+
+    ////////////// Auth server /////////////////////////////////////
+    "","",0,
+
+    /////////////// AUX SERVERS ////////////////
+    {NULL,0,{0,NULL}}, /*aux_servers_list*/
+    0, /*udp_self_balance*/
+
+    /////////////// ALTERNATE SERVERS ////////////////
+    {NULL,0,{0,NULL}}, /*alternate_servers_list*/
+    {NULL,0,{0,NULL}}, /*tls_alternate_servers_list*/
+
+    /////////////// stop server ////////////////
+    0, /*stop_turn_server*/
+
+    /////////////// MISC PARAMS ////////////////
+    0, /* stun_only */
+    0, /* no_stun */
+    0, /* secure_stun */
+    0, /* server_relay */
+    0, /* fingerprint */
+    ':', /* rest_api_separator */
+    STUN_DEFAULT_NONCE_EXPIRATION_TIME, /* stale_nonce */
+    STUN_DEFAULT_MAX_ALLOCATE_LIFETIME, /* max_allocate_lifetime */
+    STUN_DEFAULT_CHANNEL_LIFETIME, /* channel_lifetime */
+    STUN_DEFAULT_PERMISSION_LIFETIME, /* permission_lifetime */
+    0, /* mobility */
+    TURN_CREDENTIALS_NONE, /* ct */
+    0, /* use_auth_secret_with_timestamp */
+    0, /* max_bps */
+    0, /* bps_capacity */
+    0, /* bps_capacity_allocated */
+    0, /* total_quota */
+    0, /* user_quota */
+    #if !defined(TURN_NO_PROMETHEUS)
+    0, /* prometheus disabled by default */
+    DEFAULT_PROM_SERVER_PORT, /* prometheus port */
+    0, /* prometheus username labelling disabled by default when prometheus is enabled */
+    #endif
+
+    ///////////// Users DB //////////////
+    { (TURN_USERDB_TYPE)0, {"\0","\0"}, {0,NULL, {NULL,0}} },
+
+    ///////////// CPUs //////////////////
+    DEFAULT_CPUS_NUMBER,
+
+    ///////// Encryption /////////
+    "", /* secret_key_file */
+    "", /* secret_key */
+    ALLOCATION_DEFAULT_ADDRESS_FAMILY_IPV4,  /* allocation_default_address_family */
+    0,  /* no_auth_pings */
+    0,  /* no_dynamic_ip_list */
+    0,  /* no_dynamic_realms */
+
+    0,  /* log_binding */
+    0,	/* no_stun_backward_compatibility */
+    0	/* response_origin_only_with_rfc5780 */
 };
 
 //////////////// OpenSSL Init //////////////////////
@@ -193,13 +255,16 @@ static void openssl_setup(void);
 */
 
 //////////// Common static process params ////////
-
+#if defined(WINDOWS)
+//TODO: implement it!!!
+#else
 static gid_t procgroupid = 0;
 static uid_t procuserid = 0;
 static gid_t procgroupid_set = 0;
 static uid_t procuserid_set = 0;
 static char procusername[1025]="\0";
 static char procgroupname[1025]="\0";
+#endif
 
 ////////////// Configuration functionality ////////////////////////////////
 
@@ -211,7 +276,231 @@ static void reload_ssl_certs(evutil_socket_t sock, short events, void *args);
 static int make_local_listeners_list(void)
 {
 	int ret = 0;
+#if defined(WINDOWS)
+
+    DWORD dwSize = 0;
+    DWORD dwRetVal = 0;
+
+    unsigned int i = 0;
+
+    // Set the flags to pass to GetAdaptersAddresses
+    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+    // default to unspecified address family (both)
+    ULONG family = AF_UNSPEC;
+
+    LPVOID lpMsgBuf = NULL;
+
+    PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+    ULONG outBufLen = 0;
+    ULONG Iterations = 0;
+
+    PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+    PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
+    PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
+    IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
+    IP_ADAPTER_PREFIX *pPrefix = NULL;
+
+    // Allocate a 15 KB buffer to start with.
+    outBufLen = WORKING_BUFFER_SIZE;
+
+    do {
+
+        pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
+        if (pAddresses == NULL) {
+            TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+                "Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+            return -1;
+        }
 
+        dwRetVal =
+            GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
+
+        if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
+            FREE(pAddresses);
+            pAddresses = NULL;
+        }
+        else {
+            break;
+        }
+
+        Iterations++;
+
+    } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
+
+    if (dwRetVal == NO_ERROR) {
+        // If successful, output some information from the data we received
+        pCurrAddresses = pAddresses;
+        while (pCurrAddresses) {
+            /*
+            printf("\tLength of the IP_ADAPTER_ADDRESS struct: %ld\n",
+                pCurrAddresses->Length);
+            printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex);
+            printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName);//*/
+
+            pUnicast = pCurrAddresses->FirstUnicastAddress;
+            if (pUnicast != NULL) {
+                //printf("\tNumber of Unicast Addresses:\n");
+                for (i = 0; pUnicast != NULL; pUnicast = pUnicast->Next)
+                {
+                    char saddr[INET6_ADDRSTRLEN] = "";
+                    if (AF_INET == pUnicast->Address.lpSockaddr->sa_family) // IPV4
+                    {
+                        if (!inet_ntop(PF_INET,
+                            &((struct sockaddr_in*)pUnicast->Address.lpSockaddr)->sin_addr,
+                            saddr, INET6_ADDRSTRLEN))
+                            continue;
+                        if (strstr(saddr, "169.254.") == saddr)
+                            continue;
+                        if (!strcmp(saddr, "0.0.0.0"))
+                            continue;
+                    }
+                    else if (AF_INET6 == pUnicast->Address.lpSockaddr->sa_family) // IPV6
+                    {
+                        if (!inet_ntop(PF_INET6,
+                            &((struct sockaddr_in6*)pUnicast->Address.lpSockaddr)->sin6_addr,
+                            saddr, INET6_ADDRSTRLEN))
+                            continue;
+                        if (strstr(saddr, "fe80") == saddr)
+                            continue;
+                        if (!strcmp(saddr, "::"))
+                            continue;
+                    }
+                    else
+                        continue;
+
+                    //printf("\t\tIP: %s\n", saddr);
+                    
+                    add_listener_addr(saddr);
+
+                    if (MIB_IF_TYPE_LOOPBACK != pCurrAddresses->IfType)
+                        ret++;
+                }
+            }
+            /*
+            else
+                printf("\tNo Unicast Addresses\n");
+
+            pAnycast = pCurrAddresses->FirstAnycastAddress;
+            if (pAnycast) {
+                for (i = 0; pAnycast != NULL; i++)
+                    pAnycast = pAnycast->Next;
+                printf("\tNumber of Anycast Addresses: %d\n", i);
+            }
+            else
+                printf("\tNo Anycast Addresses\n");
+
+            pMulticast = pCurrAddresses->FirstMulticastAddress;
+            if (pMulticast) {
+                for (i = 0; pMulticast != NULL; i++)
+                    pMulticast = pMulticast->Next;
+                printf("\tNumber of Multicast Addresses: %d\n", i);
+            }
+            else
+                printf("\tNo Multicast Addresses\n");
+
+            pDnServer = pCurrAddresses->FirstDnsServerAddress;
+            if (pDnServer) {
+                for (i = 0; pDnServer != NULL; i++)
+                    pDnServer = pDnServer->Next;
+                printf("\tNumber of DNS Server Addresses: %d\n", i);
+            }
+            else
+                printf("\tNo DNS Server Addresses\n");
+
+            printf("\tDNS Suffix: %wS\n", pCurrAddresses->DnsSuffix);
+            printf("\tDescription: %wS\n", pCurrAddresses->Description);
+            printf("\tFriendly name: %wS\n", pCurrAddresses->FriendlyName);
+
+            if (pCurrAddresses->PhysicalAddressLength != 0) {
+                printf("\tPhysical address: ");
+                for (i = 0; i < (int)pCurrAddresses->PhysicalAddressLength;
+                    i++) {
+                    if (i == (pCurrAddresses->PhysicalAddressLength - 1))
+                        printf("%.2X\n",
+                        (int)pCurrAddresses->PhysicalAddress[i]);
+                    else
+                        printf("%.2X-",
+                        (int)pCurrAddresses->PhysicalAddress[i]);
+                }
+            }
+            printf("\tFlags: %ld\n", pCurrAddresses->Flags);
+            printf("\tMtu: %lu\n", pCurrAddresses->Mtu);
+            char* pType = NULL;
+            
+            switch (pCurrAddresses->IfType)
+            {
+            case MIB_IF_TYPE_ETHERNET:
+                pType = "ETHERNET";
+                break;
+            case MIB_IF_TYPE_PPP:
+                pType = "PPP";
+                break;
+            case MIB_IF_TYPE_LOOPBACK:
+                pType = "LOOPBACK";
+                break;
+            case MIB_IF_TYPE_SLIP:
+                pType = "ATM";
+                break;
+            case IF_TYPE_IEEE80211:
+                pType = "WIFI";
+                break;
+            }
+            printf("\tIfType: %ld (%s)\n", pCurrAddresses->IfType, pType);
+            printf("\tOperStatus: %ld\n", pCurrAddresses->OperStatus);
+            printf("\tIpv6IfIndex (IPv6 interface): %u\n",
+                pCurrAddresses->Ipv6IfIndex);
+            printf("\tZoneIndices (hex): ");
+            for (i = 0; i < 16; i++)
+                printf("%lx ", pCurrAddresses->ZoneIndices[i]);
+            printf("\n");
+
+            printf("\tTransmit link speed: %I64u\n", pCurrAddresses->TransmitLinkSpeed);
+            printf("\tReceive link speed: %I64u\n", pCurrAddresses->ReceiveLinkSpeed);
+
+            pPrefix = pCurrAddresses->FirstPrefix;
+            if (pPrefix) {
+                for (i = 0; pPrefix != NULL; i++)
+                    pPrefix = pPrefix->Next;
+                printf("\tNumber of IP Adapter Prefix entries: %d\n", i);
+            }
+            else
+                printf("\tNumber of IP Adapter Prefix entries: 0\n");
+
+            printf("\n");//*/
+
+            pCurrAddresses = pCurrAddresses->Next;
+        }
+    }
+    else {
+        TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+            "Call to GetAdaptersAddresses failed with error: %d\n",
+            dwRetVal);
+        if (dwRetVal == ERROR_NO_DATA)
+            TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+                "\tNo addresses were found for the requested parameters\n");
+        else {
+
+            if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                // Default language
+                (LPTSTR)& lpMsgBuf, 0, NULL)) {
+                TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "\tError: %s", lpMsgBuf);
+                LocalFree(lpMsgBuf);
+                if (pAddresses)
+                    FREE(pAddresses);
+                return -2;
+            }
+        }
+    }
+
+    if (pAddresses) {
+        FREE(pAddresses);
+    }
+
+#else
 	struct ifaddrs * ifs = NULL;
 	struct ifaddrs * ifa = NULL;
 
@@ -254,12 +543,116 @@ static int make_local_listeners_list(void)
 		}
 		freeifaddrs(ifs);
 	}
+#endif
 
 	return ret;
 }
 
 static int make_local_relays_list(int allow_local, int family)
 {
+	int counter = 0;
+
+#if defined(WINDOWS)
+    DWORD dwRetVal = 0;
+    // Set the flags to pass to GetAdaptersAddresses
+    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+    // default to unspecified address family (both)
+    ULONG fm = AF_UNSPEC;
+
+    LPVOID lpMsgBuf = NULL;
+
+    PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+    ULONG outBufLen = 0;
+    ULONG Iterations = 0;
+
+    PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+
+    // Allocate a 15 KB buffer to start with.
+    outBufLen = WORKING_BUFFER_SIZE;
+
+    do {
+
+        pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
+        if (pAddresses == NULL) {
+            TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+                "Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+            return -1;
+        }
+
+        dwRetVal =
+            GetAdaptersAddresses(fm, flags, NULL, pAddresses, &outBufLen);
+
+        if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
+            FREE(pAddresses);
+            pAddresses = NULL;
+        }
+        else {
+            break;
+        }
+
+        Iterations++;
+
+    } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
+
+    if (dwRetVal == NO_ERROR) {
+        // If successful, output some information from the data we received
+        pCurrAddresses = pAddresses;
+        while (pCurrAddresses) {
+            /*
+            printf("\tLength of the IP_ADAPTER_ADDRESS struct: %ld\n",
+                pCurrAddresses->Length);
+            printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex);
+            printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName);//*/
+
+            pUnicast = pCurrAddresses->FirstUnicastAddress;
+            if (pUnicast != NULL) {
+                //printf("\tNumber of Unicast Addresses:\n");
+                for (; pUnicast != NULL; pUnicast = pUnicast->Next) {
+                    if (!allow_local && (MIB_IF_TYPE_LOOPBACK == pCurrAddresses->IfType))
+                        continue;
+
+                    char saddr[INET6_ADDRSTRLEN] = "";
+                    if (AF_INET == pUnicast->Address.lpSockaddr->sa_family) // IPV4
+                    {
+                        if (family != AF_INET)
+                            continue;
+                        if (!inet_ntop(PF_INET, &((struct sockaddr_in*)pUnicast->Address.lpSockaddr)->sin_addr, saddr, INET6_ADDRSTRLEN))
+                            continue;
+                        if (strstr(saddr, "169.254.") == saddr)
+                            continue;
+                        if (!strcmp(saddr, "0.0.0.0"))
+                            continue;
+                    }
+                    else if (AF_INET6 == pUnicast->Address.lpSockaddr->sa_family) // IPV6
+                    {
+                        if (family != AF_INET6)
+                            continue;
+
+                        if (!inet_ntop(PF_INET6, &((struct sockaddr_in6*)pUnicast->Address.lpSockaddr)->sin6_addr, saddr, INET6_ADDRSTRLEN))
+                            continue;
+                        if (strstr(saddr, "fe80") == saddr)
+                            continue;
+                        if (!strcmp(saddr, "::"))
+                            continue;
+                    }
+                    else
+                        continue;
+
+                    if (add_relay_addr(saddr) > 0) {
+                        counter += 1;
+                    }
+                }
+            }
+            pCurrAddresses = pCurrAddresses->Next;
+        }
+    }
+
+    if (pAddresses) {
+        FREE(pAddresses);
+    }
+#else
 	struct ifaddrs * ifs = NULL;
 	struct ifaddrs * ifa = NULL;
 
@@ -267,8 +660,6 @@ static int make_local_relays_list(int allow_local, int family)
 
 	getifaddrs(&ifs);
 
-	int counter = 0;
-
 	if (ifs) {
 		for (ifa = ifs; ifa != NULL; ifa = ifa->ifa_next) {
 
@@ -316,17 +707,120 @@ static int make_local_relays_list(int allow_local, int family)
 		}
 		freeifaddrs(ifs);
 	}
+#endif
 
 	return counter;
 }
 
 int get_a_local_relay(int family, ioa_addr *relay_addr)
 {
-	struct ifaddrs * ifs = NULL;
-
+    int ret = -1;
 	int allow_local = 0;
 
-	int ret = -1;
+#if defined(WINDOWS)
+    DWORD dwRetVal = 0;
+    // Set the flags to pass to GetAdaptersAddresses
+    ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+    // default to unspecified address family (both)
+    ULONG fm = AF_UNSPEC;
+
+    LPVOID lpMsgBuf = NULL;
+
+    PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+    ULONG outBufLen = 0;
+    ULONG Iterations = 0;
+
+    PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+    PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+
+    outBufLen = WORKING_BUFFER_SIZE;
+
+    do {
+
+        pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
+        if (pAddresses == NULL) {
+            TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
+                "Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+            return -1;
+        }
+
+        dwRetVal =
+            GetAdaptersAddresses(fm, flags, NULL, pAddresses, &outBufLen);
+
+        if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
+            FREE(pAddresses);
+            pAddresses = NULL;
+        }
+        else {
+            break;
+        }
+
+        Iterations++;
+
+    } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
+
+    if (dwRetVal == NO_ERROR) {
+    galr_start:
+        // If successful, output some information from the data we received
+        pCurrAddresses = pAddresses;
+        while (pCurrAddresses) {
+            pUnicast = pCurrAddresses->FirstUnicastAddress;
+            if (pUnicast != NULL) {
+                //printf("\tNumber of Unicast Addresses:\n");
+                for (; pUnicast != NULL; pUnicast = pUnicast->Next) {
+                    if (!allow_local && (MIB_IF_TYPE_LOOPBACK == pCurrAddresses->IfType))
+                        continue;
+
+                    char saddr[INET6_ADDRSTRLEN] = "";
+                    if (AF_INET == pUnicast->Address.lpSockaddr->sa_family) // IPV4
+                    {
+                        if (family != AF_INET)
+                            continue;
+                        if (!inet_ntop(PF_INET, &((struct sockaddr_in*)pUnicast->Address.lpSockaddr)->sin_addr, saddr, INET6_ADDRSTRLEN))
+                            continue;
+                        if (strstr(saddr, "169.254.") == saddr)
+                            continue;
+                        if (!strcmp(saddr, "0.0.0.0"))
+                            continue;
+                    }
+                    else if (AF_INET6 == pUnicast->Address.lpSockaddr->sa_family) // IPV6
+                    {
+                        if (family != AF_INET6)
+                            continue;
+
+                        if (!inet_ntop(PF_INET6, &((struct sockaddr_in6*)pUnicast->Address.lpSockaddr)->sin6_addr, saddr, INET6_ADDRSTRLEN))
+                            continue;
+                        if (strstr(saddr, "fe80") == saddr)
+                            continue;
+                        if (!strcmp(saddr, "::"))
+                            continue;
+}
+                    else
+                        continue;
+
+                    if (make_ioa_addr((const uint8_t*)saddr, 0, relay_addr) < 0) {
+                        continue;
+                    } else {
+                        ret = 0;
+                        break;
+                    }
+                }
+            }
+            pCurrAddresses = pCurrAddresses->Next;
+        }
+
+        if (ret < 0 && !allow_local) {
+            allow_local = 1;
+            goto galr_start;
+        }
+    }
+
+    if (pAddresses) {
+        FREE(pAddresses);
+    }
+#else
+	struct ifaddrs * ifs = NULL;
 
 	char saddr[INET6_ADDRSTRLEN] = "";
 
@@ -397,8 +891,8 @@ int get_a_local_relay(int family, ioa_addr *relay_addr)
 
 		freeifaddrs(ifs);
 	}
-
 	return -1;
+#endif
 }
 
 //////////////////////////////////////////////////
@@ -1128,7 +1622,7 @@ void generate_aes_128_key(char* filePath, unsigned char* returnedKey){
 	for(i = 0; i < 16; i++){
 		fputc(key[i], fptr);
 	}
-	strcpy((char*)returnedKey, key);
+	STRCPY((char*)returnedKey, key);
 	fclose(fptr);
 
 
@@ -1317,6 +1811,9 @@ static void set_option(int c, char *value)
   case WEB_ADMIN_LISTEN_ON_WORKERS_OPT:
 	  turn_params.web_admin_listen_on_workers = get_bool_value(value);
 	  break;
+#if defined(WINDOWS)
+	  //TODO: implement it!!!
+#else
   case PROC_USER_OPT: {
 	  struct passwd* pwd = getpwnam(value);
 	  if(!pwd) {
@@ -1341,6 +1838,7 @@ static void set_option(int c, char *value)
 		}
 	}
 	break;
+#endif
 	case 'i':
 		STRCPY(turn_params.relay_ifname, value);
 		break;
@@ -2231,6 +2729,9 @@ static void set_network_engine(void)
 
 static void drop_privileges(void)
 {
+#if defined(WINDOWS)
+	//TODO: implement it!!!
+#else
 	setgroups(0, NULL);
 	if(procgroupid_set) {
 		if(getgid() != procgroupid) {
@@ -2257,15 +2758,16 @@ static void drop_privileges(void)
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Keep UID: %s(%lu)\n", procusername, (unsigned long)procuserid);
 		}
 	}
+#endif
 }
 
 static void init_domain(void)
 {
 #if !defined(TURN_NO_GETDOMAINNAME)
-	if(getdomainname(turn_params.domain,sizeof(turn_params.domain)-1)<0) {
-		turn_params.domain[0]=0;
-	} else if(!strcmp(turn_params.domain,"(none)")) {
-		turn_params.domain[0]=0;
+	if (getdomainname(turn_params.domain, sizeof(turn_params.domain) - 1) < 0) {
+		turn_params.domain[0] = 0;
+	} else if (!strcmp(turn_params.domain, "(none)")) {
+		turn_params.domain[0] = 0;
 	}
 #endif
 }
@@ -2276,6 +2778,8 @@ int main(int argc, char **argv)
 
 	IS_TURN_SERVER = 1;
 
+	TURN_MUTEX_INIT(&turn_params.tls_mutex);
+
 	set_execdir();
 
 	init_super_memory();
@@ -2341,25 +2845,23 @@ int main(int argc, char **argv)
 	turn_params.no_dtls = 1;
 #endif
 
-#if defined(_SC_NPROCESSORS_ONLN)
-
 	{
-		 turn_params.cpus = (long)sysconf(_SC_NPROCESSORS_CONF);
-
-		 if(turn_params.cpus<DEFAULT_CPUS_NUMBER)
+		int cpus = get_system_number_of_cpus();
+		if (0 < cpus)
+			turn_params.cpus = get_system_number_of_cpus();
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "System cpu num is %d\n", turn_params.cpus);
+		if (turn_params.cpus < DEFAULT_CPUS_NUMBER)
 			 turn_params.cpus = DEFAULT_CPUS_NUMBER;
-		 else if(turn_params.cpus>MAX_NUMBER_OF_GENERAL_RELAY_SERVERS)
+		else if (turn_params.cpus > MAX_NUMBER_OF_GENERAL_RELAY_SERVERS)
 			 turn_params.cpus = MAX_NUMBER_OF_GENERAL_RELAY_SERVERS;
 
 		 turn_params.general_relay_servers_number = (turnserver_id)turn_params.cpus;
 	}
 
-#endif
-
-	memset(&turn_params.default_users_db,0,sizeof(default_users_db_t));
+	memset(&turn_params.default_users_db, 0, sizeof(default_users_db_t));
 	turn_params.default_users_db.ram_db.static_accounts = ur_string_map_create(free);
 
-	if(strstr(argv[0],"turnadmin"))
+	if(strstr(argv[0], "turnadmin"))
 		return adminmain(argc,argv);
 	// Zero pass apply the log options.
 	read_config_file(argc,argv,0);
@@ -2555,6 +3057,12 @@ int main(int argc, char **argv)
 		}
 	}
 
+	if (socket_init()) return -1;
+
+#if defined(WINDOWS)
+
+    //TODO: implement deamon!!! use windows server
+#else
 	if(turn_params.turn_daemon) {
 #if !defined(TURN_HAS_DAEMON)
 		pid_t pid = fork();
@@ -2611,11 +3119,16 @@ int main(int argc, char **argv)
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "pid file created: %s\n", s);
 		}
 	}
+#endif
 
 	setup_server();
 
+#if defined(WINDOWS)
+	//TODO: implement it!!! add windows server
+#else
 	struct event *ev = evsignal_new(turn_params.listener.event_base, SIGUSR2, reload_ssl_certs, NULL);
 	event_add(ev, NULL);
+#endif
 
 	drop_privileges();
 #if !defined(TURN_NO_PROMETHEUS)
@@ -2645,7 +3158,7 @@ int main(int argc, char **argv)
 #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
 
 //array larger than anything that OpenSSL may need:
-static pthread_mutex_t mutex_buf[256];
+static TURN_MUTEX_DECLARE(mutex_buf[256]);
 static int mutex_buf_initialized = 0;
 
 void coturn_locking_function(int mode, int n, const char *file, int line);
@@ -2654,9 +3167,9 @@ void coturn_locking_function(int mode, int n, const char *file, int line) {
   UNUSED_ARG(line);
   if(mutex_buf_initialized && (n < CRYPTO_num_locks())) {
 	  if (mode & CRYPTO_LOCK)
-		  pthread_mutex_lock(&(mutex_buf[n]));
+		  TURN_MUTEX_LOCK(&(mutex_buf[n]));
 	  else
-		  pthread_mutex_unlock(&(mutex_buf[n]));
+		  TURN_MUTEX_UNLOCK(&(mutex_buf[n]));
   }
 }
 
@@ -2670,7 +3183,7 @@ void coturn_id_function(CRYPTO_THREADID *ctid)
 static int THREAD_setup(void) {
     int i;
 	for (i = 0; i < CRYPTO_num_locks(); i++) {
-		pthread_mutex_init(&(mutex_buf[i]), NULL);
+		TURN_MUTEX_INIT(&(mutex_buf[i]));
 	}
 
 	mutex_buf_initialized = 1;
@@ -2679,7 +3192,6 @@ static int THREAD_setup(void) {
 	return 1;
 }
 
-int THREAD_cleanup(void);
 int THREAD_cleanup(void) {
     int i;
 
@@ -2689,7 +3201,7 @@ int THREAD_cleanup(void) {
     CRYPTO_THREADID_set_callback(NULL);
     CRYPTO_set_locking_callback(NULL);
     for (i = 0; i < CRYPTO_num_locks(); i++) {
-        pthread_mutex_destroy(&(mutex_buf[i]));
+	  TURN_MUTEX_DESTROY(&(mutex_buf[i]));
     }
 
     mutex_buf_initialized = 0;
@@ -2700,7 +3212,6 @@ static int THREAD_setup(void) {
     return 1;
 }
 
-int THREAD_cleanup(void);
 int THREAD_cleanup(void){
     return 1;
 }
@@ -3193,7 +3704,7 @@ static void openssl_setup(void)
 
 static void openssl_load_certificates(void)
 {
-	pthread_mutex_lock(&turn_params.tls_mutex);
+	TURN_MUTEX_LOCK(&turn_params.tls_mutex);
 	if(!turn_params.no_tls) {
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
         set_ctx(&turn_params.tls_ctx,"TLS", TLSv1_2_server_method()); /*openssl-1.0.2 version specific API */
@@ -3258,7 +3769,7 @@ static void openssl_load_certificates(void)
 		TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "DTLS cipher suite: %s\n",turn_params.cipher_list);
 #endif
 	}
-	pthread_mutex_unlock(&turn_params.tls_mutex);
+	TURN_MUTEX_UNLOCK(&turn_params.tls_mutex);
 }
 
 static void reload_ssl_certs(evutil_socket_t sock, short events, void *args)

+ 12 - 7
src/apps/relay/mainrelay.h

@@ -35,12 +35,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
 #include <limits.h>
-#include <ifaddrs.h>
-#include <getopt.h>
+
 #include <locale.h>
-#include <libgen.h>
 
 #include <pthread.h>
 #include <sched.h>
@@ -48,13 +45,21 @@
 #include <signal.h>
 
 #include <sys/types.h>
-#include <sys/time.h>
 #include <sys/stat.h>
+
+#include <getopt.h>
+
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+    || defined(__DARWIN__) || defined(__MACH__)
+#include <ifaddrs.h>
+#include <libgen.h>
+#include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/utsname.h>
 
 #include <pwd.h>
 #include <grp.h>
+#endif
 
 #include <event2/bufferevent.h>
 #include <event2/buffer.h>
@@ -197,7 +202,7 @@ typedef struct _turn_params_ {
   int no_dtls;
 
   struct event *tls_ctx_update_ev;
-  pthread_mutex_t tls_mutex;
+  TURN_MUTEX_DECLARE(tls_mutex)
 
 //////////////// Common params ////////////////////
 
@@ -251,7 +256,6 @@ typedef struct _turn_params_ {
   vint allow_loopback_peers;
 
   char relay_ifname[1025];
-
   size_t relays_number;
   char **relay_addrs;
   int default_relays;
@@ -280,6 +284,7 @@ typedef struct _turn_params_ {
   turn_server_addrs_list_t alternate_servers_list;
   turn_server_addrs_list_t tls_alternate_servers_list;
 
+/////////////// stop server ////////////////
   int stop_turn_server;
 
 ////////////// MISC PARAMS ////////////////

+ 36 - 31
src/apps/relay/netengine.c

@@ -103,13 +103,13 @@ static void barrier_wait_func(const char* func, int line)
 
 /////////////// Bandwidth //////////////////
 
-static pthread_mutex_t mutex_bps;
+static TURN_MUTEX_DECLARE(mutex_bps);
 
 static band_limit_t allocate_bps(band_limit_t bps, int positive)
 {
 	band_limit_t ret = 0;
 	if(bps>0) {
-		pthread_mutex_lock(&mutex_bps);
+		TURN_MUTEX_LOCK(&mutex_bps);
 
 		if(positive) {
 
@@ -136,7 +136,7 @@ static band_limit_t allocate_bps(band_limit_t bps, int positive)
 			}
 		}
 
-		pthread_mutex_unlock(&mutex_bps);
+		TURN_MUTEX_UNLOCK(&mutex_bps);
 	}
 
 	return ret;
@@ -145,42 +145,42 @@ static band_limit_t allocate_bps(band_limit_t bps, int positive)
 band_limit_t get_bps_capacity_allocated(void)
 {
 	band_limit_t ret = 0;
-	pthread_mutex_lock(&mutex_bps);
+	TURN_MUTEX_LOCK(&mutex_bps);
 	ret = turn_params.bps_capacity_allocated;
-	pthread_mutex_unlock(&mutex_bps);
+	TURN_MUTEX_UNLOCK(&mutex_bps);
 	return ret;
 }
 
 band_limit_t get_bps_capacity(void)
 {
 	band_limit_t ret = 0;
-	pthread_mutex_lock(&mutex_bps);
+	TURN_MUTEX_LOCK(&mutex_bps);
 	ret = turn_params.bps_capacity;
-	pthread_mutex_unlock(&mutex_bps);
+	TURN_MUTEX_UNLOCK(&mutex_bps);
 	return ret;
 }
 
 void set_bps_capacity(band_limit_t value)
 {
-	pthread_mutex_lock(&mutex_bps);
+	TURN_MUTEX_LOCK(&mutex_bps);
 	turn_params.bps_capacity = value;
-	pthread_mutex_unlock(&mutex_bps);
+	TURN_MUTEX_UNLOCK(&mutex_bps);
 }
 
 band_limit_t get_max_bps(void)
 {
 	band_limit_t ret = 0;
-	pthread_mutex_lock(&mutex_bps);
+	TURN_MUTEX_LOCK(&mutex_bps);
 	ret = turn_params.max_bps;
-	pthread_mutex_unlock(&mutex_bps);
+	TURN_MUTEX_UNLOCK(&mutex_bps);
 	return ret;
 }
 
 void set_max_bps(band_limit_t value)
 {
-	pthread_mutex_lock(&mutex_bps);
+	TURN_MUTEX_LOCK(&mutex_bps);
 	turn_params.max_bps = value;
-	pthread_mutex_unlock(&mutex_bps);
+	TURN_MUTEX_UNLOCK(&mutex_bps);
 }
 
 /////////////// AUX SERVERS ////////////////
@@ -215,7 +215,7 @@ static void add_alt_server(const char *saddr, int default_port, turn_server_addr
 	if(saddr && list) {
 		ioa_addr addr;
 
-		turn_mutex_lock(&(list->m));
+		TURN_MUTEX_LOCK(&(list->m));
 
 		if(make_ioa_addr_from_full_string((const uint8_t*)saddr, default_port, &addr)!=0) {
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong IP address format: %s\n",saddr);
@@ -229,7 +229,7 @@ static void add_alt_server(const char *saddr, int default_port, turn_server_addr
 			}
 		}
 
-		turn_mutex_unlock(&(list->m));
+		TURN_MUTEX_UNLOCK(&(list->m));
 	}
 }
 
@@ -239,7 +239,7 @@ static void del_alt_server(const char *saddr, int default_port, turn_server_addr
 
 		ioa_addr addr;
 
-		turn_mutex_lock(&(list->m));
+		TURN_MUTEX_LOCK(&(list->m));
 
 		if(make_ioa_addr_from_full_string((const uint8_t*)saddr, default_port, &addr)!=0) {
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong IP address format: %s\n",saddr);
@@ -279,7 +279,7 @@ static void del_alt_server(const char *saddr, int default_port, turn_server_addr
 			}
 		}
 
-		turn_mutex_unlock(&(list->m));
+		TURN_MUTEX_UNLOCK(&(list->m));
 	}
 }
 
@@ -334,13 +334,13 @@ static void update_ssl_ctx(evutil_socket_t sock, short events, update_ssl_ctx_cb
 	turn_params_t *params = args->params;
 
 	/* No mutex with "e" as these are only used in the same event loop */
-	pthread_mutex_lock(&turn_params.tls_mutex);
+	TURN_MUTEX_LOCK(&turn_params.tls_mutex);
 	replace_one_ssl_ctx(&e->tls_ctx, params->tls_ctx);
 #if DTLS_SUPPORTED
 	replace_one_ssl_ctx(&e->dtls_ctx, params->dtls_ctx);
 #endif
 	struct event *next = args->next;
-	pthread_mutex_unlock(&turn_params.tls_mutex);
+	TURN_MUTEX_UNLOCK(&turn_params.tls_mutex);
 
 	if (next != NULL)
 		event_active(next, EV_READ, 0);
@@ -361,10 +361,10 @@ void set_ssl_ctx(ioa_engine_handle e, turn_params_t *params)
 	struct event_base *base = e->event_base;
 	if (base != NULL) {
 		struct event *ev = event_new(base, -1, EV_PERSIST, (event_callback_fn)update_ssl_ctx, (void *)args);
-		pthread_mutex_lock(&turn_params.tls_mutex);
+		TURN_MUTEX_LOCK(&turn_params.tls_mutex);
 		args->next = params->tls_ctx_update_ev;
 		params->tls_ctx_update_ev = ev;
-		pthread_mutex_unlock(&turn_params.tls_mutex);
+		TURN_MUTEX_UNLOCK(&turn_params.tls_mutex);
 	}
 }
 
@@ -479,16 +479,16 @@ static struct relay_server* get_relay_server(turnserver_id id) {
 	return rs;
 }
 
-static pthread_mutex_t auth_message_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
+static TURN_MUTEX_DECLARE(auth_message_counter_mutex);
 static authserver_id auth_message_counter = 1;
 
 void send_auth_message_to_auth_server(struct auth_message *am)
 {
-	pthread_mutex_lock(&auth_message_counter_mutex);
+	TURN_MUTEX_LOCK(&auth_message_counter_mutex);
 	if(auth_message_counter>=authserver_number) auth_message_counter = 1;
 	else if(auth_message_counter<1) auth_message_counter = 1;
 	authserver_id sn = auth_message_counter++;
-	pthread_mutex_unlock(&auth_message_counter_mutex);
+	TURN_MUTEX_UNLOCK(&auth_message_counter_mutex);
 
 	struct evbuffer *output = bufferevent_get_output(authserver[sn].out_buf);
 	if(evbuffer_add(output,am,sizeof(struct auth_message))<0) {
@@ -591,7 +591,7 @@ static int send_socket_to_relay(turnserver_id id, uint64_t cid, stun_tid *tid, i
 	int ret = -1;
 
 	struct message_to_relay sm;
-	memset(&sm,0, sizeof(struct message_to_relay));
+	memset(&sm, 0, sizeof(struct message_to_relay));
 	sm.t = rmt;
 
 	ioa_socket_handle s_to_delete = s;
@@ -691,7 +691,7 @@ int send_session_cancellation_to_relay(turnsession_id sid)
 	int ret = 0;
 
 	struct message_to_relay sm;
-	memset(&sm,0,sizeof(struct message_to_relay));
+	memset(&sm, 0, sizeof(struct message_to_relay));
 	sm.t = RMT_CANCEL_SESSION;
 
 	turnserver_id id = (turnserver_id)(sid / TURN_SESSION_ID_FACTOR);
@@ -912,7 +912,7 @@ static void listener_receive_message(struct bufferevent *bev, void *ptr)
 					    	  TURN_LOG_LEVEL_ERROR,
 					    	       "%s: Wrong general relay number: %d, total %d\n",
 					    	       __FUNCTION__,(int)ri,(int)get_real_general_relay_servers_number());
-				} else if(general_relay_servers[ri]->thr == pthread_self()) {
+				} else if(pthread_equal(general_relay_servers[ri]->thr, pthread_self())) {
 					relay_thread_index=ri;
 					break;
 				}
@@ -1724,7 +1724,7 @@ static void* run_auth_server_thread(void *arg)
 
 	} else {
 
-		memset(as,0,sizeof(struct auth_server));
+		memset(as, 0, sizeof(struct auth_server));
 
 		as->id = id;
 
@@ -1785,7 +1785,7 @@ static void* run_admin_server_thread(void *arg)
 
 static void setup_admin_server(void)
 {
-	memset(&adminserver,0,sizeof(struct admin_server));
+	memset(&adminserver, 0, sizeof(struct admin_server));
 	adminserver.listen_fd = -1;
 	adminserver.verbose = turn_params.verbose;
 
@@ -1799,9 +1799,14 @@ static void setup_admin_server(void)
 
 void setup_server(void)
 {
+#if defined(WINDOWS)
+	evthread_use_windows_threads();
+#else
 	evthread_use_pthreads();
+#endif
 
-	pthread_mutex_init(&mutex_bps, NULL);
+	TURN_MUTEX_INIT(&mutex_bps);
+    TURN_MUTEX_INIT(&auth_message_counter_mutex);
 
 	authserver_number = 1 + (authserver_id)(turn_params.cpus / 2);
 
@@ -1870,7 +1875,7 @@ void setup_server(void)
 
 void init_listener(void)
 {
-	memset(&turn_params.listener,0,sizeof(struct listener_server));
+	memset(&turn_params.listener, 0, sizeof(struct listener_server));
 }
 
 ///////////////////////////////

+ 20 - 22
src/apps/relay/ns_ioalib_engine_impl.c

@@ -920,8 +920,7 @@ ioa_socket_handle create_unbound_relay_ioa_socket(ioa_engine_handle e, int famil
 		return NULL;
 	}
 
-	ret = (ioa_socket*)malloc(sizeof(ioa_socket));
-	memset(ret,0,sizeof(ioa_socket));
+	ret = (ioa_socket*)calloc(sizeof(ioa_socket), 1);
 
 	ret->magic = SOCKET_MAGIC;
 
@@ -1364,8 +1363,7 @@ ioa_socket_handle create_ioa_socket_from_fd(ioa_engine_handle e,
 		return NULL;
 	}
 
-	ret = (ioa_socket*)malloc(sizeof(ioa_socket));
-	memset(ret,0,sizeof(ioa_socket));
+	ret = (ioa_socket*)calloc(sizeof(ioa_socket), 1);
 
 	ret->magic = SOCKET_MAGIC;
 
@@ -1640,7 +1638,7 @@ ioa_socket_handle detach_ioa_socket(ioa_socket_handle s)
 
 		ioa_network_buffer_delete(s->e, s->defer_nbh);
 
-		ret = (ioa_socket*)malloc(sizeof(ioa_socket));
+		ret = (ioa_socket*)calloc(sizeof(ioa_socket), 1);
 		if(!ret) {
 			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,"%s: Cannot allocate new socket structure\n",__FUNCTION__);
 			if(udp_fd>=0)
@@ -1967,7 +1965,10 @@ static int socket_readerr(evutil_socket_t fd, ioa_addr *orig_addr)
 		return -1;
 
 #if defined(CMSG_SPACE) && defined(MSG_ERRQUEUE) && defined(IP_RECVERR)
-
+	#ifdef _MSC_VER
+	    //TODO: implement it!!!
+	    TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "The socket_readerr is not implement in _MSC_VER");
+	#else
 	uint8_t ecmsg[TURN_CMSG_SZ+1];
 	int flags = MSG_ERRQUEUE;
 	int len = 0;
@@ -2000,6 +2001,7 @@ static int socket_readerr(evutil_socket_t fd, ioa_addr *orig_addr)
 
 	} while((len>0)&&(try_cycle++<MAX_ERRORS_IN_UDP_BATCH));
 
+	#endif
 #endif
 
 	return 0;
@@ -2022,7 +2024,7 @@ int udp_recvfrom(evutil_socket_t fd, ioa_addr* orig_addr, const ioa_addr *like_a
 	recv_ttl_t recv_ttl = TTL_DEFAULT;
 	recv_tos_t recv_tos = TOS_DEFAULT;
 
-#if !defined(CMSG_SPACE)
+#if defined(_MSC_VER) || !defined(CMSG_SPACE)
 	do {
 	  len = recvfrom(fd, buffer, buf_size, flags, (struct sockaddr*) orig_addr, (socklen_t*) &slen);
 	} while (len < 0 && (errno == EINTR));
@@ -2629,7 +2631,7 @@ static int socket_input_worker(ioa_socket_handle s)
 			if(s->read_cb) {
 				ioa_net_data nd;
 
-				memset(&nd,0,sizeof(ioa_net_data));
+				memset(&nd, 0, sizeof(ioa_net_data));
 				addr_cpy(&(nd.src_addr),&remote_addr);
 				nd.nbh = buf_elem;
 				nd.recv_ttl = ttl;
@@ -3862,7 +3864,7 @@ const char* get_ioa_socket_tls_method(ioa_socket_handle s)
 #define TURN_SM_SIZE (1024<<11)
 
 struct _super_memory {
-	pthread_mutex_t mutex_sm;
+	TURN_MUTEX_DECLARE(mutex_sm)
 	char **super_memory;
 	size_t *sm_allocated;
 	size_t sm_total_sz;
@@ -3873,11 +3875,10 @@ struct _super_memory {
 static void init_super_memory_region(super_memory_t *r)
 {
 	if(r) {
-		memset(r,0,sizeof(super_memory_t));
+		memset(r, 0, sizeof(super_memory_t));
 
 		r->super_memory = (char**)malloc(sizeof(char*));
-		r->super_memory[0] = (char*)malloc(TURN_SM_SIZE);
-		memset(r->super_memory[0],0,TURN_SM_SIZE);
+		r->super_memory[0] = (char*)calloc(1, TURN_SM_SIZE);
 
 		r->sm_allocated = (size_t*)malloc(sizeof(size_t*));
 		r->sm_allocated[0] = 0;
@@ -3886,9 +3887,9 @@ static void init_super_memory_region(super_memory_t *r)
 		r->sm_chunk = 0;
 
 		while(r->id == 0)
-			r->id = (uint32_t)random();
+			r->id = (uint32_t)turn_random();
 
-		pthread_mutex_init(&r->mutex_sm, NULL);
+		TURN_MUTEX_INIT(&r->mutex_sm);
 	}
 }
 
@@ -3913,12 +3914,11 @@ void* allocate_super_memory_region_func(super_memory_t *r, size_t size, const ch
 	void *ret = NULL;
 
 	if(!r) {
-		ret = malloc(size);
-		memset(ret, 0, size);
+		ret = calloc(1, size);
 		return ret;
 	}
 
-	pthread_mutex_lock(&r->mutex_sm);
+	TURN_MUTEX_LOCK(&r->mutex_sm);
 
 	size = ((size_t)((size+sizeof(void*))/(sizeof(void*)))) * sizeof(void*);
 
@@ -3947,8 +3947,7 @@ void* allocate_super_memory_region_func(super_memory_t *r, size_t size, const ch
 		if(!region) {
 			r->sm_chunk += 1;
 			r->super_memory = (char**)realloc(r->super_memory,(r->sm_chunk+1) * sizeof(char*));
-			r->super_memory[r->sm_chunk] = (char*)malloc(TURN_SM_SIZE);
-			memset(r->super_memory[r->sm_chunk],0,TURN_SM_SIZE);
+			r->super_memory[r->sm_chunk] = (char*)calloc(1, TURN_SM_SIZE);
 			r->sm_allocated = (size_t*)realloc(r->sm_allocated,(r->sm_chunk+1) * sizeof(size_t*));
 			r->sm_allocated[r->sm_chunk] = 0;
 			region = r->super_memory[r->sm_chunk];
@@ -3966,11 +3965,10 @@ void* allocate_super_memory_region_func(super_memory_t *r, size_t size, const ch
 		}
 	}
 
-	pthread_mutex_unlock(&r->mutex_sm);
+	TURN_MUTEX_UNLOCK(&r->mutex_sm);
 
 	if(!ret) {
-		ret = malloc(size);
-		memset(ret, 0, size);
+		ret = calloc(1, size);
 	}
 
 	return ret;

+ 32 - 6
src/apps/relay/turn_admin_server.c

@@ -32,11 +32,32 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
+
+#if defined(_MSC_VER)
+#include <direct.h>
+#else
 #include <unistd.h>
+#endif
+
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+	|| defined(__DARWIN__) || defined(__MACH__)
+#include <ifaddrs.h>
+#include <libgen.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#endif
+
+#include <limits.h>
+
+#include <getopt.h>
+#include <locale.h>
+
+#include <signal.h>
 
 #include "libtelnet.h"
 
-#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <event2/bufferevent.h>
 #include <event2/buffer.h>
@@ -652,8 +673,12 @@ static void cli_print_configuration(struct cli_session* cs)
 		cli_print_flag(cs,turn_params.mobility,"mobility",1);
 		cli_print_flag(cs,turn_params.udp_self_balance,"udp-self-balance",0);
 		cli_print_str(cs,turn_params.pidfile,"pidfile",0);
+#if defined(WINDOWS)
+		//TODO: implement it!!!
+#else
 		cli_print_uint(cs,(unsigned long)getuid(),"process user ID",0);
 		cli_print_uint(cs,(unsigned long)getgid(),"process group ID",0);
+#endif
 
 		{
 			char wd[1025];
@@ -1143,8 +1168,7 @@ static void cliserver_input_handler(struct evconnlistener *l, evutil_socket_t fd
 
 	addr_debug_print(adminserver.verbose, (ioa_addr*)sa,"CLI connected to");
 
-	struct cli_session *clisession = (struct cli_session*)malloc(sizeof(struct cli_session));
-	memset(clisession,0,sizeof(struct cli_session));
+	struct cli_session *clisession = (struct cli_session*)calloc(sizeof(struct cli_session), 1);
 
 	clisession->rp = get_realm(NULL);
 
@@ -2057,9 +2081,12 @@ static void write_pc_page(ioa_socket_handle s)
 				https_print_flag(sb,turn_params.mobility,"mobility","mobility");
 				https_print_flag(sb,turn_params.udp_self_balance,"udp-self-balance",0);
 				https_print_str(sb,turn_params.pidfile,"pidfile",0);
+#if defined(WINDOWS)
+				//TODO: implement it!!!
+#else
 				https_print_uint(sb,(unsigned long)getuid(),"process user ID",0);
 				https_print_uint(sb,(unsigned long)getgid(),"process group ID",0);
-
+#endif
 				{
 					char wd[1025];
 					if(getcwd(wd,sizeof(wd)-1)) {
@@ -3283,8 +3310,7 @@ static void handle_logon_request(ioa_socket_handle s, struct http_request* hr)
 
 		struct admin_session* as = (struct admin_session*)s->special_session;
 		if(!as) {
-			as = (struct admin_session*)malloc(sizeof(struct admin_session));
-			memset(as,0,sizeof(struct admin_session));
+			as = (struct admin_session*)calloc(sizeof(struct admin_session), 1);
 			s->special_session = as;
 			s->special_session_size = sizeof(struct admin_session);
 		}

+ 2 - 2
src/apps/relay/turn_ports.c

@@ -90,8 +90,8 @@ static void turnports_randomize(turnports* tp) {
     unsigned int i=0;
     unsigned int cycles=size*10;
     for(i=0;i<cycles;i++) {
-      uint16_t port1 = (uint16_t)(tp->low + (uint16_t)(((unsigned long)random())%((unsigned long)size)));
-      uint16_t port2 = (uint16_t)(tp->low + (uint16_t)(((unsigned long)random())%((unsigned long)size)));
+      uint16_t port1 = (uint16_t)(tp->low + (uint16_t)(((unsigned long)turn_random())%((unsigned long)size)));
+      uint16_t port2 = (uint16_t)(tp->low + (uint16_t)(((unsigned long)turn_random())%((unsigned long)size)));
       if(port1!=port2) {
     	  int pos1=tp->status[port1];
     	  int pos2=tp->status[port2];

+ 24 - 15
src/apps/relay/userdb.c

@@ -32,11 +32,21 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <pthread.h>
+#include <limits.h>
+#include <getopt.h>
+#include <locale.h>
 
-#include <sys/resource.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <event2/bufferevent.h>
+#include <event2/buffer.h>
 
 #include "userdb.h"
 #include "dbdrivers/dbdriver.h"
@@ -54,7 +64,7 @@
 static realm_params_t *default_realm_params_ptr = NULL;
 
 static ur_string_map *realms = NULL;
-static turn_mutex o_to_realm_mutex;
+static TURN_MUTEX_DECLARE(o_to_realm_mutex);
 static ur_string_map *o_to_realm = NULL;
 static secrets_list_t realms_list;
 
@@ -1065,8 +1075,8 @@ void run_db_test(void)
 static pthread_rwlock_t* whitelist_rwlock = NULL;
 static pthread_rwlock_t* blacklist_rwlock = NULL;
 #else
-static turn_mutex whitelist_mutex;
-static turn_mutex blacklist_mutex;
+static TURN_MUTEX_DECLARE(whitelist_mutex);
+static TURN_MUTEX_DECLARE(blacklist_mutex);
 #endif
 
 static ip_range_list_t* ipwhitelist = NULL;
@@ -1081,8 +1091,8 @@ void init_dynamic_ip_lists(void)
 	blacklist_rwlock = (pthread_rwlock_t*) malloc(sizeof(pthread_rwlock_t));
 	pthread_rwlock_init(blacklist_rwlock, NULL);
 #else
-	turn_mutex_init(&whitelist_mutex);
-	turn_mutex_init(&blacklist_mutex);
+	TURN_MUTEX_INIT(&whitelist_mutex);
+	TURN_MUTEX_INIT(&blacklist_mutex);
 #endif
 }
 
@@ -1092,7 +1102,7 @@ void ioa_lock_whitelist(ioa_engine_handle e)
 #if !defined(TURN_NO_RWLOCK)
 	pthread_rwlock_rdlock(whitelist_rwlock);
 #else
-	turn_mutex_lock(&whitelist_mutex);
+	TURN_MUTEX_LOCK(&whitelist_mutex);
 #endif
 }
 void ioa_unlock_whitelist(ioa_engine_handle e)
@@ -1101,7 +1111,7 @@ void ioa_unlock_whitelist(ioa_engine_handle e)
 #if !defined(TURN_NO_RWLOCK)
 	pthread_rwlock_unlock(whitelist_rwlock);
 #else
-	turn_mutex_unlock(&whitelist_mutex);
+	TURN_MUTEX_UNLOCK(&whitelist_mutex);
 #endif
 }
 static void ioa_wrlock_whitelist(ioa_engine_handle e)
@@ -1110,7 +1120,7 @@ static void ioa_wrlock_whitelist(ioa_engine_handle e)
 #if !defined(TURN_NO_RWLOCK)
 	pthread_rwlock_wrlock(whitelist_rwlock);
 #else
-	turn_mutex_lock(&whitelist_mutex);
+	TURN_MUTEX_LOCK(&whitelist_mutex);
 #endif
 }
 const ip_range_list_t* ioa_get_whitelist(ioa_engine_handle e)
@@ -1125,7 +1135,7 @@ void ioa_lock_blacklist(ioa_engine_handle e)
 #if !defined(TURN_NO_RWLOCK)
 	pthread_rwlock_rdlock(blacklist_rwlock);
 #else
-	turn_mutex_lock(&blacklist_mutex);
+	TURN_MUTEX_LOCK(&blacklist_mutex);
 #endif
 }
 void ioa_unlock_blacklist(ioa_engine_handle e)
@@ -1134,7 +1144,7 @@ void ioa_unlock_blacklist(ioa_engine_handle e)
 #if !defined(TURN_NO_RWLOCK)
 	pthread_rwlock_unlock(blacklist_rwlock);
 #else
-	turn_mutex_unlock(&blacklist_mutex);
+	TURN_MUTEX_UNLOCK(&blacklist_mutex);
 #endif
 }
 static void ioa_wrlock_blacklist(ioa_engine_handle e)
@@ -1143,7 +1153,7 @@ static void ioa_wrlock_blacklist(ioa_engine_handle e)
 #if !defined(TURN_NO_RWLOCK)
 	pthread_rwlock_wrlock(blacklist_rwlock);
 #else
-	turn_mutex_lock(&blacklist_mutex);
+	TURN_MUTEX_LOCK(&blacklist_mutex);
 #endif
 }
 const ip_range_list_t* ioa_get_blacklist(ioa_engine_handle e)
@@ -1154,8 +1164,7 @@ const ip_range_list_t* ioa_get_blacklist(ioa_engine_handle e)
 
 ip_range_list_t* get_ip_list(const char *kind)
 {
-	ip_range_list_t *ret = (ip_range_list_t*) malloc(sizeof(ip_range_list_t));
-	memset(ret,0,sizeof(ip_range_list_t));
+	ip_range_list_t *ret = (ip_range_list_t*) calloc(sizeof(ip_range_list_t), 1);
 
 	const turn_dbdriver_t * dbd = get_dbdriver();
 	if (dbd && dbd->get_ip_list && !turn_params.no_dynamic_ip_list) {

+ 9 - 1
src/apps/rfc5769/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnutils_rfc5769check)
 
@@ -8,7 +8,15 @@ set(SOURCE_FILES
 
 add_executable(${PROJECT_NAME} ${SOURCE_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turnclient)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    )
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )

+ 5 - 1
src/apps/rfc5769/rfc5769check.c

@@ -28,12 +28,16 @@
  * SUCH DAMAGE.
  */
 
-#include <err.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
+
+#if defined(_MSC_VER)
+#include <getopt.h>
+#else
 #include <unistd.h>
+#endif
 
 #include "ns_turn_utils.h"
 #include "apputils.h"

+ 9 - 1
src/apps/stunclient/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnutils_stunclient)
 
@@ -8,7 +8,15 @@ set(SOURCE_FILES
 
 add_executable(${PROJECT_NAME} ${SOURCE_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turnclient)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    )
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )

+ 10 - 2
src/apps/stunclient/stunclient.c

@@ -28,12 +28,18 @@
  * SUCH DAMAGE.
  */
 
-#include <err.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
+#if defined(_MSC_VER)
+    #include <getopt.h>
+#else
+    #include <unistd.h>
+    #if !defined(WINDOWS)
+        #include <err.h>
+    #endif
+#endif
 
 #include "ns_turn_utils.h"
 #include "apputils.h"
@@ -415,6 +421,8 @@ int main(int argc, char **argv)
   int c=0;
   int forceRfc5780 = 0;
 
+  if (socket_init()) return -1;
+
   set_logfile("stdout");
   set_system_parameters(0);
   

+ 9 - 1
src/apps/uclient/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnutils_uclient)
 
@@ -10,7 +10,15 @@ set(SOURCE_FILES
 
 add_executable(${PROJECT_NAME} ${SOURCE_FILES})
 target_link_libraries(${PROJECT_NAME} PRIVATE turnclient)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    )
 INSTALL(TARGETS ${PROJECT_NAME}
     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
         COMPONENT Runtime
     )
+install(DIRECTORY
+        $<TARGET_FILE_DIR:${PROJECT_NAME}>/
+    DESTINATION DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        COMPONENT Runtime
+    )

+ 23 - 2
src/apps/uclient/mainuclient.c

@@ -38,9 +38,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
 
-#include "ns_turn_openssl.h"
+#if defined(_MSC_VER)
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
 
 /////////////// extern definitions /////////////////////
 
@@ -169,6 +172,24 @@ int main(int argc, char **argv)
 	char rest_api_separator = ':';
 	int use_null_cipher=0;
 
+#if defined(WINDOWS)
+
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	int err;
+
+	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
+	wVersionRequested = MAKEWORD(2, 2);
+
+	err = WSAStartup(wVersionRequested, &wsaData);
+	if (err != 0) {
+		/* Tell the user that we could not find a usable */
+		/* Winsock DLL.                                  */
+		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "WSAStartup failed with error: %d\n", err);
+		return 1;
+	}
+#endif
+
 	set_logfile("stdout");
 
 	set_execdir();

+ 36 - 37
src/apps/uclient/startuclient.c

@@ -28,7 +28,9 @@
  * SUCH DAMAGE.
  */
 
+#if defined(__linux__)
 #include <unistd.h>
+#endif
 
 #include "apputils.h"
 #include "ns_turn_utils.h"
@@ -37,8 +39,6 @@
 #include "uclient.h"
 #include "session.h"
 
-#include "ns_turn_openssl.h"
-
 /////////////////////////////////////////
 
 #define MAX_CONNECT_EFFORTS (77)
@@ -60,14 +60,14 @@ static const size_t kALPNProtosLen = sizeof(kALPNProtos) - 1;
 int rare_event(void)
 {
 	if(dos)
-		return (((unsigned long)random()) %1000 == 777);
+		return (((unsigned long)turn_random()) %1000 == 777);
 	return 0;
 }
 
 int not_rare_event(void)
 {
 	if(dos)
-		return ((((unsigned long)random()) %1000) < 200);
+		return ((((unsigned long)turn_random()) %1000) < 200);
 	return 0;
 }
 
@@ -85,7 +85,7 @@ static int get_allocate_address_family(ioa_addr *relay_addr) {
 static SSL* tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr, int *try_again, int connect_cycle)
 {
 
-	int ctxtype = (int)(((unsigned long)random())%root_tls_ctx_num);
+	int ctxtype = (int)(((unsigned long)turn_random())%root_tls_ctx_num);
 
 	SSL *ssl;
 
@@ -402,7 +402,7 @@ static int clnet_allocate(int verbose,
 		} else if(rt) {
 			ep = -1;
 		} else if(!ep) {
-			ep = (((uint8_t)random()) % 2);
+			ep = (((uint8_t)turn_random()) % 2);
 			ep = ep-1;
 		}
 
@@ -602,10 +602,10 @@ static int clnet_allocate(int verbose,
 		  int fd = clnet_info->fd;
 		  SSL* ssl = clnet_info->ssl;
 
-		  int close_now = (int)(random()%2);
+		  int close_now = (int)(turn_random()%2);
 
 		  if(close_now) {
-			  int close_socket = (int)(random()%2);
+			  int close_socket = (int)(turn_random()%2);
 			  if(ssl && !close_socket) {
 				  SSL_shutdown(ssl);
 				  SSL_free(ssl);
@@ -659,7 +659,7 @@ static int clnet_allocate(int verbose,
 			}
 
 			if(dual_allocation && !mobility) {
-				int t = ((uint8_t)random())%3;
+				int t = ((uint8_t)turn_random())%3;
 				if(t) {
 					uint8_t field[4];
 					field[0] = (t==1) ? (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4 : (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6;
@@ -761,7 +761,7 @@ static int turn_channel_bind(int verbose, uint16_t *chn,
 		int cb_sent = 0;
 
 		if(negative_test) {
-			*chn = stun_set_channel_bind_request(&request_message, peer_addr, (uint16_t)random());
+			*chn = stun_set_channel_bind_request(&request_message, peer_addr, (uint16_t)turn_random());
 		} else {
 			*chn = stun_set_channel_bind_request(&request_message, peer_addr, *chn);
 		}
@@ -1036,19 +1036,19 @@ int start_connection(uint16_t clnet_remote_port0,
 
 			if(extra_requests) {
 				const char *sarbaddr = "164.156.178.190";
-				if(random() % 2 == 0)
+				if(turn_random() % 2 == 0)
 					sarbaddr = "2001::172";
 				ioa_addr arbaddr;
 				make_ioa_addr((const uint8_t*)sarbaddr, 333, &arbaddr);
 				int i;
-				int maxi = (unsigned short)random() % EXTRA_CREATE_PERMS;
+				int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
 				for(i=0;i<maxi;i++) {
 					uint16_t chni=0;
-					int port = (unsigned short)random();
+					int port = (unsigned short)turn_random();
 					if(port<1024) port += 1024;
 					addr_set_port(&arbaddr, port);
 					uint8_t *u=(uint8_t*)&(arbaddr.s4.sin_addr);
-					u[(unsigned short)random()%4] = u[(unsigned short)random()%4] + 1;
+					u[(unsigned short)turn_random()%4] = u[(unsigned short)turn_random()%4] + 1;
 					//char sss[128];
 					//addr_to_string(&arbaddr,(uint8_t*)sss);
 					//printf("%s: 111.111: %s\n",__FUNCTION__,sss);
@@ -1066,18 +1066,18 @@ int start_connection(uint16_t clnet_remote_port0,
 
 			if(extra_requests) {
 				const char *sarbaddr = "64.56.78.90";
-				if(random() % 2 == 0)
+				if(turn_random() % 2 == 0)
 					sarbaddr = "2001::172";
 				ioa_addr arbaddr[EXTRA_CREATE_PERMS];
 				make_ioa_addr((const uint8_t*)sarbaddr, 333, &arbaddr[0]);
 				int i;
-				int maxi = (unsigned short)random() % EXTRA_CREATE_PERMS;
+				int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
 				for(i=0;i<maxi;i++) {
 					if(i>0)
 						addr_cpy(&arbaddr[i],&arbaddr[0]);
-					addr_set_port(&arbaddr[i], (unsigned short)random());
+					addr_set_port(&arbaddr[i], (unsigned short)turn_random());
 					uint8_t *u=(uint8_t*)&(arbaddr[i].s4.sin_addr);
-					u[(unsigned short)random()%4] = u[(unsigned short)random()%4] + 1;
+					u[(unsigned short)turn_random()%4] = u[(unsigned short)turn_random()%4] + 1;
 					//char sss[128];
 					//addr_to_string(&arbaddr[i],(uint8_t*)sss);
 					//printf("%s: 111.111: %s\n",__FUNCTION__,sss);
@@ -1086,7 +1086,7 @@ int start_connection(uint16_t clnet_remote_port0,
 			}
 		} else {
 
-			int before=(random()%2 == 0);
+			int before=(turn_random()%2 == 0);
 
 			if(before) {
 				if (turn_create_permission(verbose, clnet_info, &peer_addr, 1) < 0) {
@@ -1102,18 +1102,18 @@ int start_connection(uint16_t clnet_remote_port0,
 
 			if(extra_requests) {
 				const char *sarbaddr = "64.56.78.90";
-				if(random() % 2 == 0)
+				if(turn_random() % 2 == 0)
 					sarbaddr = "2001::172";
 				ioa_addr arbaddr[EXTRA_CREATE_PERMS];
 				make_ioa_addr((const uint8_t*)sarbaddr, 333, &arbaddr[0]);
 				int i;
-				int maxi = (unsigned short)random() % EXTRA_CREATE_PERMS;
+				int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
 				for(i=0;i<maxi;i++) {
 					if(i>0)
 						addr_cpy(&arbaddr[i],&arbaddr[0]);
-					addr_set_port(&arbaddr[i], (unsigned short)random());
+					addr_set_port(&arbaddr[i], (unsigned short)turn_random());
 					uint8_t *u=(uint8_t*)&(arbaddr[i].s4.sin_addr);
-					u[(unsigned short)random()%4] = u[(unsigned short)random()%4] + 1;
+					u[(unsigned short)turn_random()%4] = u[(unsigned short)turn_random()%4] + 1;
 					//char sss[128];
 					//addr_to_string(&arbaddr,(uint8_t*)sss);
 					//printf("%s: 111.111: %s\n",__FUNCTION__,sss);
@@ -1274,19 +1274,19 @@ int start_c2c_connection(uint16_t clnet_remote_port0,
 
 		if(extra_requests) {
 			const char *sarbaddr = "164.156.178.190";
-			if(random() % 2 == 0)
+			if(turn_random() % 2 == 0)
 				sarbaddr = "2001::172";
 			ioa_addr arbaddr;
 			make_ioa_addr((const uint8_t*)sarbaddr, 333, &arbaddr);
 			int i;
-			int maxi = (unsigned short)random() % EXTRA_CREATE_PERMS;
+			int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
 			for(i=0;i<maxi;i++) {
 				uint16_t chni=0;
-				int port = (unsigned short)random();
+				int port = (unsigned short)turn_random();
 				if(port<1024) port += 1024;
 				addr_set_port(&arbaddr, port);
 				uint8_t *u=(uint8_t*)&(arbaddr.s4.sin_addr);
-				u[(unsigned short)random()%4] = u[(unsigned short)random()%4] + 1;
+				u[(unsigned short)turn_random()%4] = u[(unsigned short)turn_random()%4] + 1;
 				//char sss[128];
 				//addr_to_string(&arbaddr,(uint8_t*)sss);
 				//printf("%s: 111.111: %s\n",__FUNCTION__,sss);
@@ -1298,18 +1298,18 @@ int start_c2c_connection(uint16_t clnet_remote_port0,
 
 		if(extra_requests) {
 			const char *sarbaddr = "64.56.78.90";
-			if(random() % 2 == 0)
+			if(turn_random() % 2 == 0)
 				sarbaddr = "2001::172";
 			ioa_addr arbaddr[EXTRA_CREATE_PERMS];
 			make_ioa_addr((const uint8_t*)sarbaddr, 333, &arbaddr[0]);
 			int i;
-			int maxi = (unsigned short)random() % EXTRA_CREATE_PERMS;
+			int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
 			for(i=0;i<maxi;i++) {
 				if(i>0)
 					addr_cpy(&arbaddr[i],&arbaddr[0]);
-				addr_set_port(&arbaddr[i], (unsigned short)random());
+				addr_set_port(&arbaddr[i], (unsigned short)turn_random());
 				uint8_t *u=(uint8_t*)&(arbaddr[i].s4.sin_addr);
-				u[(unsigned short)random()%4] = u[(unsigned short)random()%4] + 1;
+				u[(unsigned short)turn_random()%4] = u[(unsigned short)turn_random()%4] + 1;
 				//char sss[128];
 				//addr_to_string(&arbaddr[i],(uint8_t*)sss);
 				//printf("%s: 111.111: %s\n",__FUNCTION__,sss);
@@ -1341,16 +1341,16 @@ int start_c2c_connection(uint16_t clnet_remote_port0,
 
 		if(extra_requests) {
 			const char *sarbaddr = "64.56.78.90";
-			if(random() % 2 == 0)
+			if(turn_random() % 2 == 0)
 				sarbaddr = "2001::172";
 			ioa_addr arbaddr;
 			make_ioa_addr((const uint8_t*)sarbaddr, 333, &arbaddr);
 			int i;
-			int maxi = (unsigned short)random() % EXTRA_CREATE_PERMS;
+			int maxi = (unsigned short)turn_random() % EXTRA_CREATE_PERMS;
 			for(i=0;i<maxi;i++) {
-				addr_set_port(&arbaddr, (unsigned short)random());
+				addr_set_port(&arbaddr, (unsigned short)turn_random());
 				uint8_t *u=(uint8_t*)&(arbaddr.s4.sin_addr);
-				u[(unsigned short)random()%4] = u[(unsigned short)random()%4] + 1;
+				u[(unsigned short)turn_random()%4] = u[(unsigned short)turn_random()%4] + 1;
 				//char sss[128];
 				//addr_to_string(&arbaddr,(uint8_t*)sss);
 				//printf("%s: 111.111: %s\n",__FUNCTION__,sss);
@@ -1545,8 +1545,7 @@ void tcp_data_connect(app_ur_session *elem, uint32_t cid)
 	++elem->pinfo.tcp_conn_number;
 	int i = (int)(elem->pinfo.tcp_conn_number-1);
 	elem->pinfo.tcp_conn=(app_tcp_conn_info**)realloc(elem->pinfo.tcp_conn,elem->pinfo.tcp_conn_number*sizeof(app_tcp_conn_info*));
-	elem->pinfo.tcp_conn[i]=(app_tcp_conn_info*)malloc(sizeof(app_tcp_conn_info));
-	memset(elem->pinfo.tcp_conn[i],0,sizeof(app_tcp_conn_info));
+	elem->pinfo.tcp_conn[i]=(app_tcp_conn_info*)calloc(sizeof(app_tcp_conn_info), 1);
 
 	elem->pinfo.tcp_conn[i]->tcp_data_fd = clnet_fd;
 	elem->pinfo.tcp_conn[i]->cid = cid;

+ 13 - 14
src/apps/uclient/uclient.c

@@ -34,12 +34,11 @@
 #include "ns_turn_utils.h"
 #include "session.h"
 
+#if defined(__linux__)
 #include <unistd.h>
-#include <time.h>
-
-#include "ns_turn_openssl.h"
-
 #include <sys/select.h>
+#endif
+#include <time.h>
 
 static int verbose_packets=0;
 
@@ -197,11 +196,11 @@ int send_buffer(app_ur_conn_info *clnet_info, stun_buffer* message, int data_con
 	char *buffer = (char*) (message->buf);
 
 	if(negative_protocol_test && (message->len>0)) {
-		if(random()%10 == 0) {
-			int np = (int)((unsigned long)random()%10);
+		if(turn_random()%10 == 0) {
+			int np = (int)((unsigned long)turn_random()%10);
 			while(np-->0) {
-				int pos = (int)((unsigned long)random()%(unsigned long)message->len);
-				int val = (int)((unsigned long)random()%256);
+				int pos = (int)((unsigned long)turn_random()%(unsigned long)message->len);
+				int val = (int)((unsigned long)turn_random()%256);
 				message->buf[pos]=(uint8_t)val;
 			}
 		}
@@ -700,7 +699,7 @@ static int client_read(app_ur_session *elem, int is_tcp_data, app_tcp_conn_info
 				  sar = stun_attr_get_next_str(elem->in_buffer.buf,elem->in_buffer.len,sar);
 			  }
 			  if(negative_test) {
-				  tcp_data_connect(elem,(uint64_t)random());
+				  tcp_data_connect(elem,(uint64_t)turn_random());
 			  } else {
 				  /* positive test */
 				  tcp_data_connect(elem,cid);
@@ -890,7 +889,7 @@ static int client_write(app_ur_session *elem) {
 	if (!(elem->pinfo.tcp_conn) || !(elem->pinfo.tcp_conn_number)) {
 		return -1;
 	}
-	int i = (unsigned int)(random()) % elem->pinfo.tcp_conn_number;
+	int i = (unsigned int)(turn_random()) % elem->pinfo.tcp_conn_number;
 	atc = elem->pinfo.tcp_conn[i];
 	if(!atc->tcp_data_bound) {
 		printf("%s: Uninitialized atc: i=%d, atc=0x%lx\n",__FUNCTION__,i,(long)atc);
@@ -1237,7 +1236,7 @@ static int refresh_channel(app_ur_session* elem, uint16_t method, uint32_t lt)
 		stun_attr_add(&message, STUN_ATTRIBUTE_LIFETIME, (const char*) &lt, 4);
 
 		if(dual_allocation && !mobility) {
-			int t = ((uint8_t)random())%3;
+			int t = ((uint8_t)turn_random())%3;
 			if(t) {
 				uint8_t field[4];
 				field[0] = (t==1) ? (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4 : (uint8_t)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6;
@@ -1528,7 +1527,7 @@ void start_mclient(const char *remote_address, int port,
 	stime = current_time;
 
 	for(i=0;i<total_clients;i++) {
-		elems[i]->to_send_timems = current_mstime + 1000 + ((uint32_t)random())%5000;
+		elems[i]->to_send_timems = current_mstime + 1000 + ((uint32_t)turn_random())%5000;
 	}
 
 	tot_messages = elems[0]->tot_msgnum * total_clients;
@@ -1612,7 +1611,7 @@ int add_integrity(app_ur_conn_info *clnet_info, stun_buffer *message)
 			if(((method == STUN_METHOD_ALLOCATE) || (method == STUN_METHOD_REFRESH)) || !(clnet_info->key_set))
 			{
 
-				cok=((unsigned short)random())%3;
+				cok=((unsigned short)turn_random())%3;
 				clnet_info->cok = cok;
 				oauth_token otoken;
 				encoded_oauth_token etoken;
@@ -1621,7 +1620,7 @@ int add_integrity(app_ur_conn_info *clnet_info, stun_buffer *message)
 				long halflifetime = OAUTH_SESSION_LIFETIME/2;
 				long random_lifetime = 0;
 				while(!random_lifetime) {
-					random_lifetime = random();
+					random_lifetime = turn_random();
 				}
 				if(random_lifetime<0) random_lifetime=-random_lifetime;
 				random_lifetime = random_lifetime % halflifetime;

+ 17 - 9
src/client/CMakeLists.txt

@@ -1,9 +1,7 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turnclient)
 
-find_package(OpenSSL REQUIRED)
-
 set(HEADER_FILES
     ${CMAKE_SOURCE_DIR}/src/ns_turn_defs.h
     ${CMAKE_SOURCE_DIR}/src/client++/TurnMsgLib.h
@@ -20,13 +18,16 @@ set(SOURCE_FILES
     ns_turn_msg.c
     )
 
-add_library(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES})
+add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${HEADER_FILES})
 
-target_link_libraries(${PROJECT_NAME} PUBLIC turncommon OpenSSL::SSL OpenSSL::Crypto)
+target_link_libraries(${PROJECT_NAME} PUBLIC turncommon)
 
 # Install head files
 set_target_properties(${PROJECT_NAME} PROPERTIES
-    PUBLIC_HEADER "${HEADER_FILES}"
+    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/
+    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/
+    PUBLIC_HEADER "${HEADER_FILES}"  # Install head files
     VERSION ${VERSION}
     )
 
@@ -37,21 +38,27 @@ INSTALL(TARGETS ${PROJECT_NAME}
     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
         COMPONENT Runtime
     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        COMPONENT Development
     PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/turn/client
+		COMPONENT Development
     INCLUDES DESTINATION
-        ${CMAKE_INSTALL_INCLUDEDIR}
         ${CMAKE_INSTALL_INCLUDEDIR}/turn
         ${CMAKE_INSTALL_INCLUDEDIR}/turn/client
+        COMPONENT Development
     )
 
 export(TARGETS ${PROJECT_NAME}
     APPEND FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+    NAMESPACE coturn::
     )
 
 # Install cmake configure files
 install(EXPORT ${PROJECT_NAME}Config
-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake"
+    NAMESPACE coturn::
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+    COMPONENT Development
     )
+
 # Install cmake version configure file
 if(DEFINED VERSION)
     write_basic_package_version_file(
@@ -59,5 +66,6 @@ if(DEFINED VERSION)
         VERSION ${VERSION}
         COMPATIBILITY AnyNewerVersion)
     install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
-        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake")
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+		    COMPONENT Development)
 endif()

+ 5 - 2
src/client/ns_turn_ioaddr.c

@@ -29,8 +29,11 @@
  */
 
 #include "ns_turn_ioaddr.h"
-#include <netdb.h>
-#include <string.h>
+
+#if defined(__unix__) || defined(unix) || defined(__APPLE__) \
+	|| defined(__DARWIN__) || defined(__MACH__)
+	#include <netdb.h>
+#endif
 
 //////////////////////////////////////////////////////////////
 

+ 11 - 7
src/client/ns_turn_msg.c

@@ -96,8 +96,12 @@ int stun_method_str(uint16_t method, char *smethod)
 long turn_random(void)
 {
 	long ret = 0;
-	if(!RAND_bytes((unsigned char *)&ret,sizeof(ret)))
+	if (!RAND_bytes((unsigned char*)&ret, sizeof(ret)))
+#if defined(WINDOWS)
+		ret = rand();
+#else
 		ret = random();
+#endif
 	return ret;
 }
 
@@ -107,7 +111,7 @@ static void turn_random_tid_size(void *id)
 	if(!RAND_pseudo_bytes((unsigned char *)ar,12)) {
 		size_t i;
 		for(i=0;i<3;++i) {
-			ar[i] = (uint32_t)random();
+			ar[i] = (uint32_t)turn_random();
 		}
 	}
 }
@@ -263,7 +267,7 @@ int stun_produce_integrity_key_str(const uint8_t *uname, const uint8_t *realm, c
  		EVP_DigestUpdate(ctx,str,strl);
  		EVP_DigestFinal(ctx,key,&keylen);
  		EVP_MD_CTX_free(ctx);
-#else // OPENSSL_VERSION_NUMBER < 0x10100000L
+#else // OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER < 0x30000000L
 		unsigned int keylen = 0;
 		EVP_MD_CTX *ctx = EVP_MD_CTX_new();
 #if defined EVP_MD_CTX_FLAG_NON_FIPS_ALLOW && ! defined(LIBRESSL_VERSION_NUMBER)
@@ -1477,7 +1481,7 @@ int stun_attr_add_str(uint8_t* buf, size_t *len, uint16_t attr, const uint8_t* a
     if(alen>0) memcpy(attr_start+4,avalue,alen);
 	
 	// Write 0 padding to not leak data
-	memset(attr_start+4+alen, 0, paddinglen);
+    memset(attr_start + 4 + alen, 0, paddinglen);
 
     return 0;
   }
@@ -1986,7 +1990,7 @@ int stun_check_message_integrity_by_key_str(turn_credential_type ct, uint8_t *bu
 	if(!old_hmac)
 		return -1;
 
-	if(bcmp(old_hmac,new_hmac,shasize))
+	if(memcmp(old_hmac,new_hmac,shasize))
 		return 0;
 
 	return +1;
@@ -2429,7 +2433,7 @@ int decode_oauth_token_normal(const uint8_t *server_name, const encoded_oauth_to
 		    	return -1;
 		    }
 
-		    if(bcmp(check_mac,mac,mac_size)) {
+		    if(memcmp(check_mac,mac,mac_size)) {
 		    	OAUTH_ERROR("%s: token integrity check failed\n",__FUNCTION__);
 		    	return -1;
 		    }
@@ -2478,7 +2482,7 @@ static void generate_random_nonce(unsigned char *nonce, size_t sz) {
 	if(!RAND_bytes(nonce, (int)sz)) {
 		size_t i;
 		for(i=0;i<sz;++i) {
-			nonce[i] = (unsigned char)random();
+			nonce[i] = (unsigned char)turn_random();
 		}
 	}
 }

+ 10 - 3
src/ns_turn_defs.h

@@ -43,19 +43,26 @@
 #define __APPLE_USE_RFC_3542
 #endif
 
-#include <sys/types.h>
+#if defined(WINDOWS)
+#include <ws2tcpip.h>
+#include <Windows.h>
+#include <process.h>
+#else
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <net/if.h>
+#include <strings.h>
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
 #include <ctype.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
-#include <unistd.h>
 #include <inttypes.h>
 #include <time.h>
 #include <stdarg.h>

+ 18 - 5
src/server/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Author: Kang Lin ([email protected])
+# Author: Kang Lin <[email protected]>
 
 project(turn_server)
 
@@ -19,7 +19,7 @@ set(HEADER_FILES
     ns_turn_session.h
     )
 
-add_library(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES})
+add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${HEADER_FILES})
 
 target_link_libraries(${PROJECT_NAME} PUBLIC turnclient)
 
@@ -30,6 +30,10 @@ target_include_directories(${PROJECT_NAME} PUBLIC
 
 # Install head files
 set_target_properties(${PROJECT_NAME} PROPERTIES
+    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
+    PUBLIC_HEADER "${HEADER_FILES}"  # Install head files
     VERSION ${VERSION}
     )
 
@@ -40,20 +44,28 @@ INSTALL(TARGETS ${PROJECT_NAME}
     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
         COMPONENT Runtime
     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        COMPONENT Development
+    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/turn/server
+		COMPONENT Development
     INCLUDES DESTINATION
-        ${CMAKE_INSTALL_INCLUDEDIR}
         ${CMAKE_INSTALL_INCLUDEDIR}/turn
         ${CMAKE_INSTALL_INCLUDEDIR}/turn/client
+		${CMAKE_INSTALL_INCLUDEDIR}/turn/server
+        COMPONENT Development
     )
 
 export(TARGETS ${PROJECT_NAME}
+    NAMESPACE coturn::
     APPEND FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake
     )
 
 # Install cmake configure files
 install(EXPORT ${PROJECT_NAME}Config
-    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake"
+    NAMESPACE coturn::
+    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+        COMPONENT Development
     )
+
 # Install cmake version configure file
 if(DEFINED VERSION)
     write_basic_package_version_file(
@@ -61,5 +73,6 @@ if(DEFINED VERSION)
         VERSION ${VERSION}
         COMPATIBILITY AnyNewerVersion)
     install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
-        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake")
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/coturn"
+		    COMPONENT Development)
 endif()

+ 2 - 4
src/server/ns_turn_allocation.c

@@ -486,8 +486,7 @@ ch_info *ch_map_get(ch_map* map, uint16_t chnum, int new_chn)
 		if(new_chn) {
 			size_t old_sz_mem = old_sz * sizeof(ch_info*);
 			a->extra_chns = (ch_info**)realloc(a->extra_chns,old_sz_mem + sizeof(ch_info*));
-			a->extra_chns[old_sz] = (ch_info*)malloc(sizeof(ch_info));
-			memset(a->extra_chns[old_sz],0,sizeof(ch_info));
+			a->extra_chns[old_sz] = (ch_info*)calloc(sizeof(ch_info), 1);
 			a->extra_sz += 1;
 
 			return a->extra_chns[old_sz];
@@ -574,8 +573,7 @@ tcp_connection *create_tcp_connection(uint8_t server_id, allocation *a, stun_tid
 			}
 		}
 	}
-	tcp_connection *tc = (tcp_connection*)malloc(sizeof(tcp_connection));
-	memset(tc,0,sizeof(tcp_connection));
+	tcp_connection *tc = (tcp_connection*)calloc(sizeof(tcp_connection), 1);
 	addr_cpy(&(tc->peer_addr),peer_addr);
 	if(tid)
 		memcpy(&(tc->tid),tid,sizeof(stun_tid));

+ 19 - 4
src/server/ns_turn_ioalib.h

@@ -49,6 +49,25 @@ typedef struct _ts_ur_super_session ts_ur_super_session;
 struct _tcp_connection;
 typedef struct _tcp_connection tcp_connection;
 
+#if defined(_MSC_VER)
+    #ifndef strtok_r
+        #define strtok_r strtok_s
+    #endif
+
+    #ifndef sleep
+        #define sleep(t) Sleep(t * 1000)
+	#endif
+
+    #ifndef usleep
+        #define usleep Sleep
+    #endif
+
+    #if !defined(ssize_t) && !defined(_SSIZE_T_)
+        #include <BaseTsd.h>
+        typedef SSIZE_T ssize_t;
+    #endif
+    
+#endif
 
 ////////////// Mutexes /////////////////////
 
@@ -290,10 +309,6 @@ void handle_http_echo(ioa_socket_handle s);
 
 int try_acme_redirect(char *req, size_t len, const char *url, ioa_socket_handle s);
 
-///////////// ACME /////////////////////
-
-int try_acme_redirect(char *req, size_t len, const char *url, ioa_socket_handle s);
-
 ///////////////////////////////////////
 
 #ifdef __cplusplus

+ 3 - 4
src/server/ns_turn_maps_rtcp.c

@@ -176,8 +176,7 @@ static int rtcp_map_init(rtcp_map* map, ioa_engine_handle e) {
 }
 
 rtcp_map* rtcp_map_create(ioa_engine_handle e) {
-  rtcp_map *map=(rtcp_map*)malloc(sizeof(rtcp_map));
-  memset(map,0,sizeof(rtcp_map));
+  rtcp_map *map=(rtcp_map*)calloc(sizeof(rtcp_map), 1);
   if(rtcp_map_init(map,e)<0) {
     free(map);
     return NULL;
@@ -193,9 +192,9 @@ rtcp_map* rtcp_map_create(ioa_engine_handle e) {
 int rtcp_map_put(rtcp_map* map, rtcp_token_type token, ioa_socket_handle s) {
   if(!rtcp_map_valid(map)) return -1;
   else {
-    rtcp_alloc_type *value=(rtcp_alloc_type*)malloc(sizeof(rtcp_alloc_type));
+    rtcp_alloc_type *value=(rtcp_alloc_type*)calloc(sizeof(rtcp_alloc_type), 1);
     if(!value) return -1;
-    memset(value,0,sizeof(rtcp_alloc_type));
+
     value->s=s;
     value->t=turn_time() + RTCP_TIMEOUT;
     value->token=token;

+ 4 - 5
src/server/ns_turn_server.c

@@ -213,7 +213,7 @@ void init_turn_server_addrs_list(turn_server_addrs_list_t *l)
 	if(l) {
 		l->addrs = NULL;
 		l->size = 0;
-		turn_mutex_init(&(l->m));
+		TURN_MUTEX_INIT(&(l->m));
 	}
 }
 
@@ -794,8 +794,7 @@ static ts_ur_super_session* create_new_ss(turn_turnserver* server) {
 	//
 	//printf("%s: 111.111: session size=%lu\n",__FUNCTION__,(unsigned long)sizeof(ts_ur_super_session));
 	//
-	ts_ur_super_session *ss = (ts_ur_super_session*)malloc(sizeof(ts_ur_super_session));
-	memset(ss,0,sizeof(ts_ur_super_session));
+	ts_ur_super_session *ss = (ts_ur_super_session*)calloc(sizeof(ts_ur_super_session), 1);
 	ss->server = server;
 	get_default_realm_options(&(ss->realm_options));
 	put_session_into_map(ss);
@@ -3642,9 +3641,9 @@ static int handle_turn_command(turn_turnserver *server, ts_ur_super_session *ss,
 					}
 
 					if(asl && asl->size) {
-						turn_mutex_lock(&(asl->m));
+						TURN_MUTEX_LOCK(&(asl->m));
 						set_alternate_server(asl,get_local_addr_from_ioa_socket(ss->client_socket),&(server->as_counter),method,&tid,resp_constructed,&err_code,&reason,nbh);
-						turn_mutex_unlock(&(asl->m));
+						TURN_MUTEX_UNLOCK(&(asl->m));
 					}
 				}
 			}

+ 1 - 1
src/server/ns_turn_server.h

@@ -47,7 +47,7 @@ extern "C" {
 struct _turn_server_addrs_list {
 	ioa_addr *addrs;
 	volatile size_t size;
-	turn_mutex m;
+	TURN_MUTEX_DECLARE(m)
 };
 
 typedef struct _turn_server_addrs_list turn_server_addrs_list_t;

+ 20 - 0
vcpkg.json

@@ -0,0 +1,20 @@
+{
+  "name": "coturn",
+  "version-string": "4.6.0",
+  "dependencies": [
+    {
+      "name": "pthreads",
+      "platform": "windows"
+    },
+    {
+      "name": "libevent",
+      "features": [ "openssl", "thread" ]
+    },
+    "openssl",
+    "sqlite3",
+    "libpq",
+    "hiredis",
+    "mongo-c-driver"
+  ]
+
+}