Compare commits
	
		
			2 Commits
		
	
	
		
			v9.6.3
			...
			feature/wi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ae3c94c4bb | ||
| 
						 | 
					fa88cbe268 | 
							
								
								
									
										75
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										75
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							@@ -5,82 +5,23 @@ on:
 | 
				
			|||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  linux:
 | 
					  #
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					  #   Windows with OpenSSL is working but disabled as it takes 13 minutes (10 for openssl) to build with vcpkg
 | 
				
			||||||
    steps:
 | 
					  #
 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					  windows_openssl:
 | 
				
			||||||
    - name: make test_make
 | 
					 | 
				
			||||||
      run: make test_make
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mac_tsan_sectransport:
 | 
					 | 
				
			||||||
    runs-on: macOS-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					 | 
				
			||||||
    - name: make test_tsan
 | 
					 | 
				
			||||||
      run: make test_tsan
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mac_tsan_openssl:
 | 
					 | 
				
			||||||
    runs-on: macOS-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					 | 
				
			||||||
    - name: install openssl
 | 
					 | 
				
			||||||
      run: brew install openssl@1.1
 | 
					 | 
				
			||||||
    - name: make test
 | 
					 | 
				
			||||||
      run: make test_tsan_openssl
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mac_tsan_mbedtls:
 | 
					 | 
				
			||||||
    runs-on: macOS-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					 | 
				
			||||||
    - name: install mbedtls
 | 
					 | 
				
			||||||
      run: brew install mbedtls
 | 
					 | 
				
			||||||
    - name: make test
 | 
					 | 
				
			||||||
      run: make test_tsan_mbedtls
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  windows:
 | 
					 | 
				
			||||||
    runs-on: windows-latest
 | 
					    runs-on: windows-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					    - uses: actions/checkout@v1
 | 
				
			||||||
    - uses: seanmiddleditch/gha-setup-vsdevenv@master
 | 
					    - uses: seanmiddleditch/gha-setup-vsdevenv@master
 | 
				
			||||||
 | 
					    - run: |
 | 
				
			||||||
 | 
					        vcpkg install zlib:x64-windows
 | 
				
			||||||
 | 
					        vcpkg install openssl:x64-windows
 | 
				
			||||||
    - run: |
 | 
					    - run: |
 | 
				
			||||||
        mkdir build
 | 
					        mkdir build
 | 
				
			||||||
        cd build
 | 
					        cd build
 | 
				
			||||||
        cmake -DCMAKE_CXX_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 ..
 | 
					        cmake -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_CXX_COMPILER=cl.exe -DUSE_OPEN_SSL=1 -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 ..
 | 
				
			||||||
    - run: cmake --build build
 | 
					    - run: cmake --build build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Running the unittest does not work, the binary cannot be found
 | 
					    # Running the unittest does not work, the binary cannot be found
 | 
				
			||||||
    #- run: ../build/test/ixwebsocket_unittest.exe
 | 
					    #- run: ../build/test/ixwebsocket_unittest.exe
 | 
				
			||||||
    # working-directory: test
 | 
					    # working-directory: test
 | 
				
			||||||
 | 
					 | 
				
			||||||
  uwp:
 | 
					 | 
				
			||||||
    runs-on: windows-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - uses: actions/checkout@v1
 | 
					 | 
				
			||||||
    - uses: seanmiddleditch/gha-setup-vsdevenv@master
 | 
					 | 
				
			||||||
    - run: |
 | 
					 | 
				
			||||||
        mkdir build
 | 
					 | 
				
			||||||
        cd build
 | 
					 | 
				
			||||||
        cmake -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_CXX_COMPILER=cl.exe -DUSE_TEST=1 ..
 | 
					 | 
				
			||||||
    - run: cmake --build build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Windows with OpenSSL is working but disabled as it takes 13 minutes (10 for openssl) to build with vcpkg
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   windows_openssl:
 | 
					 | 
				
			||||||
#     runs-on: windows-latest
 | 
					 | 
				
			||||||
#     steps:
 | 
					 | 
				
			||||||
#     - uses: actions/checkout@v1
 | 
					 | 
				
			||||||
#     - uses: seanmiddleditch/gha-setup-vsdevenv@master
 | 
					 | 
				
			||||||
#     - run: |
 | 
					 | 
				
			||||||
#         vcpkg install zlib:x64-windows
 | 
					 | 
				
			||||||
#         vcpkg install openssl:x64-windows
 | 
					 | 
				
			||||||
#     - run: |
 | 
					 | 
				
			||||||
#         mkdir build
 | 
					 | 
				
			||||||
#         cd build
 | 
					 | 
				
			||||||
#         cmake -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_CXX_COMPILER=cl.exe -DUSE_OPEN_SSL=1 -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 ..
 | 
					 | 
				
			||||||
#     - run: cmake --build build
 | 
					 | 
				
			||||||
# 
 | 
					 | 
				
			||||||
#     # Running the unittest does not work, the binary cannot be found
 | 
					 | 
				
			||||||
#     #- run: ../build/test/ixwebsocket_unittest.exe
 | 
					 | 
				
			||||||
#     # working-directory: test
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,19 +0,0 @@
 | 
				
			|||||||
name: Mark stale issues and pull requests
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
on:
 | 
					 | 
				
			||||||
  schedule:
 | 
					 | 
				
			||||||
  - cron: "0 0 * * *"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					 | 
				
			||||||
  stale:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - uses: actions/stale@v1
 | 
					 | 
				
			||||||
      with:
 | 
					 | 
				
			||||||
        repo-token: ${{ secrets.GITHUB_TOKEN }}
 | 
					 | 
				
			||||||
        stale-issue-message: 'Stale issue message'
 | 
					 | 
				
			||||||
        stale-pr-message: 'Stale pull request message'
 | 
					 | 
				
			||||||
        stale-issue-label: 'no-issue-activity'
 | 
					 | 
				
			||||||
        stale-pr-label: 'no-pr-activity'
 | 
					 | 
				
			||||||
@@ -1,12 +1,7 @@
 | 
				
			|||||||
repos:
 | 
					repos:
 | 
				
			||||||
-   repo: https://github.com/pre-commit/pre-commit-hooks
 | 
					-   repo: https://github.com/pre-commit/pre-commit-hooks
 | 
				
			||||||
    rev: v2.5.0
 | 
					    rev: v2.3.0
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
    -   id: check-yaml
 | 
					    -   id: check-yaml
 | 
				
			||||||
    -   id: end-of-file-fixer
 | 
					    -   id: end-of-file-fixer
 | 
				
			||||||
    -   id: trailing-whitespace
 | 
					    -   id: trailing-whitespace
 | 
				
			||||||
-   repo: https://github.com/pocc/pre-commit-hooks
 | 
					 | 
				
			||||||
    rev: v1.1.1
 | 
					 | 
				
			||||||
    hooks:
 | 
					 | 
				
			||||||
    -    id: clang-format
 | 
					 | 
				
			||||||
         args: [-i, -style=file]
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ include(FindPackageHandleStandardArgs)
 | 
				
			|||||||
find_path(JSONCPP_INCLUDE_DIRS json/json.h)
 | 
					find_path(JSONCPP_INCLUDE_DIRS json/json.h)
 | 
				
			||||||
find_library(JSONCPP_LIBRARY jsoncpp)
 | 
					find_library(JSONCPP_LIBRARY jsoncpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
find_package_handle_standard_args(JsonCpp
 | 
					find_package_handle_standard_args(JSONCPP
 | 
				
			||||||
    FOUND_VAR
 | 
					    FOUND_VAR
 | 
				
			||||||
      JSONCPP_FOUND
 | 
					      JSONCPP_FOUND
 | 
				
			||||||
    REQUIRED_VARS
 | 
					    REQUIRED_VARS
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										102
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								CMakeLists.txt
									
									
									
									
									
								
							@@ -12,10 +12,6 @@ set (CMAKE_CXX_STANDARD 14)
 | 
				
			|||||||
set (CXX_STANDARD_REQUIRED ON)
 | 
					set (CXX_STANDARD_REQUIRED ON)
 | 
				
			||||||
set (CMAKE_CXX_EXTENSIONS OFF)
 | 
					set (CMAKE_CXX_EXTENSIONS OFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 | 
					 | 
				
			||||||
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (UNIX)
 | 
					if (UNIX)
 | 
				
			||||||
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
 | 
					  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
@@ -48,11 +44,13 @@ set( IXWEBSOCKET_SOURCES
 | 
				
			|||||||
    ixwebsocket/IXWebSocketCloseConstants.cpp
 | 
					    ixwebsocket/IXWebSocketCloseConstants.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketHandshake.cpp
 | 
					    ixwebsocket/IXWebSocketHandshake.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketHttpHeaders.cpp
 | 
					    ixwebsocket/IXWebSocketHttpHeaders.cpp
 | 
				
			||||||
 | 
					    ixwebsocket/IXWebSocketMessageQueue.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketPerMessageDeflate.cpp
 | 
					    ixwebsocket/IXWebSocketPerMessageDeflate.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp
 | 
					    ixwebsocket/IXWebSocketPerMessageDeflateCodec.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp
 | 
					    ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketServer.cpp
 | 
					    ixwebsocket/IXWebSocketServer.cpp
 | 
				
			||||||
    ixwebsocket/IXWebSocketTransport.cpp
 | 
					    ixwebsocket/IXWebSocketTransport.cpp
 | 
				
			||||||
 | 
					    ixwebsocket/LUrlParser.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set( IXWEBSOCKET_HEADERS
 | 
					set( IXWEBSOCKET_HEADERS
 | 
				
			||||||
@@ -83,10 +81,10 @@ set( IXWEBSOCKET_HEADERS
 | 
				
			|||||||
    ixwebsocket/IXWebSocketCloseInfo.h
 | 
					    ixwebsocket/IXWebSocketCloseInfo.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketErrorInfo.h
 | 
					    ixwebsocket/IXWebSocketErrorInfo.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketHandshake.h
 | 
					    ixwebsocket/IXWebSocketHandshake.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketHandshakeKeyGen.h
 | 
					 | 
				
			||||||
    ixwebsocket/IXWebSocketHttpHeaders.h
 | 
					    ixwebsocket/IXWebSocketHttpHeaders.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketInitResult.h
 | 
					    ixwebsocket/IXWebSocketInitResult.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketMessage.h
 | 
					    ixwebsocket/IXWebSocketMessage.h
 | 
				
			||||||
 | 
					    ixwebsocket/IXWebSocketMessageQueue.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketMessageType.h
 | 
					    ixwebsocket/IXWebSocketMessageType.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketOpenInfo.h
 | 
					    ixwebsocket/IXWebSocketOpenInfo.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketPerMessageDeflate.h
 | 
					    ixwebsocket/IXWebSocketPerMessageDeflate.h
 | 
				
			||||||
@@ -96,6 +94,8 @@ set( IXWEBSOCKET_HEADERS
 | 
				
			|||||||
    ixwebsocket/IXWebSocketServer.h
 | 
					    ixwebsocket/IXWebSocketServer.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketTransport.h
 | 
					    ixwebsocket/IXWebSocketTransport.h
 | 
				
			||||||
    ixwebsocket/IXWebSocketVersion.h
 | 
					    ixwebsocket/IXWebSocketVersion.h
 | 
				
			||||||
 | 
					    ixwebsocket/LUrlParser.h
 | 
				
			||||||
 | 
					    ixwebsocket/libwshandshake.hpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (UNIX)
 | 
					if (UNIX)
 | 
				
			||||||
@@ -113,38 +113,31 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
 | 
				
			|||||||
    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/freebsd/IXSetThreadName_freebsd.cpp)
 | 
					    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/freebsd/IXSetThreadName_freebsd.cpp)
 | 
				
			||||||
else()
 | 
					else()
 | 
				
			||||||
    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
 | 
					    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
 | 
				
			||||||
 | 
					    list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSelectInterruptEventFd.cpp)
 | 
				
			||||||
 | 
					    list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSelectInterruptEventFd.h)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option(USE_TLS "Enable TLS support" FALSE)
 | 
					option(USE_TLS "Enable TLS support" FALSE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (USE_TLS)
 | 
					if (USE_TLS)
 | 
				
			||||||
    # default to securetranport on Apple if nothing is configured
 | 
					    option(USE_MBED_TLS "Use Mbed TLS" OFF)
 | 
				
			||||||
    if (APPLE)
 | 
					    option(USE_OPEN_SSL "Use OpenSSL" OFF)
 | 
				
			||||||
      if (NOT USE_MBED_TLS AND NOT USE_OPEN_SSL) # unless we want something else
 | 
					
 | 
				
			||||||
        set(USE_SECURE_TRANSPORT ON)
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    # default to mbedtls on windows if nothing is configured
 | 
					    # default to mbedtls on windows if nothing is configured
 | 
				
			||||||
    elseif (WIN32)
 | 
					    if (WIN32 AND NOT USE_OPEN_SSL AND NOT USE_MBED_TLS)
 | 
				
			||||||
      if (NOT USE_OPEN_SSL) # unless we want something else
 | 
					      option(USE_MBED_TLS "Use Mbed TLS" ON)
 | 
				
			||||||
        set(USE_MBED_TLS ON)
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    else() # default to OpenSSL on all other platforms
 | 
					 | 
				
			||||||
      if (NOT USE_MBED_TLS) # Unless mbedtls is requested
 | 
					 | 
				
			||||||
        set(USE_OPEN_SSL ON)
 | 
					 | 
				
			||||||
      endif()
 | 
					 | 
				
			||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (USE_MBED_TLS)
 | 
					    if (USE_MBED_TLS)
 | 
				
			||||||
        list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketMbedTLS.h)
 | 
					        list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketMbedTLS.h)
 | 
				
			||||||
        list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketMbedTLS.cpp)
 | 
					        list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketMbedTLS.cpp)
 | 
				
			||||||
    elseif (USE_SECURE_TRANSPORT)
 | 
					    elseif (APPLE AND NOT USE_OPEN_SSL)
 | 
				
			||||||
        list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
 | 
					        list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketAppleSSL.h)
 | 
				
			||||||
        list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketAppleSSL.cpp)
 | 
					        list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketAppleSSL.cpp)
 | 
				
			||||||
    elseif (USE_OPEN_SSL)
 | 
					    else()
 | 
				
			||||||
 | 
					        set(USE_OPEN_SSL ON)
 | 
				
			||||||
        list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)
 | 
					        list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSocketOpenSSL.h)
 | 
				
			||||||
        list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketOpenSSL.cpp)
 | 
					        list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSocketOpenSSL.cpp)
 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
        message(FATAL_ERROR "TLS Configuration error: unknown backend")
 | 
					 | 
				
			||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -159,49 +152,55 @@ if (USE_TLS)
 | 
				
			|||||||
        target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_MBED_TLS)
 | 
					        target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_MBED_TLS)
 | 
				
			||||||
    elseif (USE_OPEN_SSL)
 | 
					    elseif (USE_OPEN_SSL)
 | 
				
			||||||
        target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_OPEN_SSL)
 | 
					        target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_OPEN_SSL)
 | 
				
			||||||
    elseif (USE_SECURE_TRANSPORT)
 | 
					 | 
				
			||||||
        target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_SECURE_TRANSPORT)
 | 
					 | 
				
			||||||
    else()
 | 
					 | 
				
			||||||
        message(FATAL_ERROR "TLS Configuration error: unknown backend")
 | 
					 | 
				
			||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (USE_TLS)
 | 
					if (APPLE AND USE_TLS AND NOT USE_MBED_TLS AND NOT USE_OPEN_SSL)
 | 
				
			||||||
  if (USE_OPEN_SSL)
 | 
					  target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
 | 
				
			||||||
    message(STATUS "TLS configured to use openssl")
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (WIN32)
 | 
				
			||||||
 | 
					  target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
 | 
				
			||||||
 | 
					  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (UNIX)
 | 
				
			||||||
 | 
					  find_package(Threads)
 | 
				
			||||||
 | 
					  target_link_libraries(ixwebsocket ${CMAKE_THREAD_LIBS_INIT})
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (USE_TLS AND USE_OPEN_SSL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Help finding Homebrew's OpenSSL on macOS
 | 
					  # Help finding Homebrew's OpenSSL on macOS
 | 
				
			||||||
  if (APPLE)
 | 
					  if (APPLE)
 | 
				
			||||||
    set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /usr/local/opt/openssl/lib)
 | 
					    set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /usr/local/opt/openssl/lib)
 | 
				
			||||||
    set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /usr/local/opt/openssl/include)
 | 
					    set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /usr/local/opt/openssl/include)
 | 
				
			||||||
 | 
					 | 
				
			||||||
      # This is for MacPort OpenSSL 1.0
 | 
					 | 
				
			||||||
      # set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/local/lib/openssl-1.0)
 | 
					 | 
				
			||||||
      # set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /opt/local/include/openssl-1.0)
 | 
					 | 
				
			||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # This OPENSSL_FOUND check is to help find a cmake manually configured OpenSSL
 | 
					  if(NOT OPENSSL_FOUND)
 | 
				
			||||||
    if (NOT OPENSSL_FOUND)
 | 
					 | 
				
			||||||
    find_package(OpenSSL REQUIRED)
 | 
					    find_package(OpenSSL REQUIRED)
 | 
				
			||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
    message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  add_definitions(${OPENSSL_DEFINITIONS})
 | 
					  add_definitions(${OPENSSL_DEFINITIONS})
 | 
				
			||||||
    target_include_directories(ixwebsocket PUBLIC ${OPENSSL_INCLUDE_DIR})
 | 
					  message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
 | 
				
			||||||
 | 
					  include_directories(${OPENSSL_INCLUDE_DIR})
 | 
				
			||||||
  target_link_libraries(ixwebsocket ${OPENSSL_LIBRARIES})
 | 
					  target_link_libraries(ixwebsocket ${OPENSSL_LIBRARIES})
 | 
				
			||||||
  elseif (USE_MBED_TLS)
 | 
					endif()
 | 
				
			||||||
    message(STATUS "TLS configured to use mbedtls")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (USE_TLS AND USE_MBED_TLS)
 | 
				
			||||||
 | 
					  # FIXME I'm not too sure that this USE_VENDORED_THIRD_PARTY thing works
 | 
				
			||||||
 | 
					  if (USE_VENDORED_THIRD_PARTY)
 | 
				
			||||||
 | 
					    set (ENABLE_PROGRAMS OFF)
 | 
				
			||||||
 | 
					    add_subdirectory(third_party/mbedtls)
 | 
				
			||||||
 | 
					    include_directories(third_party/mbedtls/include)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target_link_libraries(ixwebsocket mbedtls)
 | 
				
			||||||
 | 
					  else()
 | 
				
			||||||
    find_package(MbedTLS REQUIRED)
 | 
					    find_package(MbedTLS REQUIRED)
 | 
				
			||||||
    target_include_directories(ixwebsocket PUBLIC ${MBEDTLS_INCLUDE_DIRS})
 | 
					    target_include_directories(ixwebsocket PUBLIC ${MBEDTLS_INCLUDE_DIRS})
 | 
				
			||||||
    target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES})
 | 
					    target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES})
 | 
				
			||||||
  elseif (USE_SECURE_TRANSPORT)
 | 
					 | 
				
			||||||
    message(STATUS "TLS configured to use secure transport")
 | 
					 | 
				
			||||||
    target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
 | 
					 | 
				
			||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# This ZLIB_FOUND check is to help find a cmake manually configured zlib
 | 
					 | 
				
			||||||
if (NOT ZLIB_FOUND)
 | 
					if (NOT ZLIB_FOUND)
 | 
				
			||||||
  find_package(ZLIB)
 | 
					  find_package(ZLIB)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
@@ -214,21 +213,6 @@ else()
 | 
				
			|||||||
  target_link_libraries(ixwebsocket zlibstatic)
 | 
					  target_link_libraries(ixwebsocket zlibstatic)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (WIN32)
 | 
					 | 
				
			||||||
  target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
 | 
					 | 
				
			||||||
  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (USE_TLS)
 | 
					 | 
				
			||||||
    target_link_libraries(ixwebsocket Crypt32)
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (UNIX)
 | 
					 | 
				
			||||||
  find_package(Threads)
 | 
					 | 
				
			||||||
  target_link_libraries(ixwebsocket ${CMAKE_THREAD_LIBS_INIT})
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set( IXWEBSOCKET_INCLUDE_DIRS
 | 
					set( IXWEBSOCKET_INCLUDE_DIRS
 | 
				
			||||||
    ${CMAKE_CURRENT_SOURCE_DIR}
 | 
					    ${CMAKE_CURRENT_SOURCE_DIR}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,3 @@ IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version.
 | 
				
			|||||||
If your company or project is using this library, feel free to open an issue or PR to amend this list.
 | 
					If your company or project is using this library, feel free to open an issue or PR to amend this list.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [Machine Zone](https://www.mz.com)
 | 
					- [Machine Zone](https://www.mz.com)
 | 
				
			||||||
- [Tokio](https://gitlab.com/HCInk/tokio), a discord library focused on audio playback with node bindings.
 | 
					 | 
				
			||||||
- [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), a work in progress discord library
 | 
					 | 
				
			||||||
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
 | 
					 | 
				
			||||||
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ FROM alpine:3.11 as build
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
RUN apk add --no-cache \
 | 
					RUN apk add --no-cache \
 | 
				
			||||||
    gcc g++ musl-dev linux-headers \
 | 
					    gcc g++ musl-dev linux-headers \
 | 
				
			||||||
    cmake mbedtls-dev make zlib-dev ninja
 | 
					    cmake mbedtls-dev make zlib-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN addgroup -S app && \
 | 
					RUN addgroup -S app && \
 | 
				
			||||||
    adduser -S -G app app && \
 | 
					    adduser -S -G app app && \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,122 +1,6 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
All changes to this project will be documented in this file.
 | 
					All changes to this project will be documented in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [9.6.3] - 2020-05-18
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cmake) revert CMake changes to fix #203 and be able to use an external OpenSSL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.6.2] - 2020-05-17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cmake) make install cmake files optional to not conflict with vcpkg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.6.1] - 2020-05-17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(windows + tls) mbedtls is the default windows tls backend + add ability to load system certificates with mbdetls on windows
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.6.0] - 2020-05-12
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixbots) add options to limit how many messages per minute should be processed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.9] - 2020-05-12
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixbots) add new class to configure a bot to simplify passing options around
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.8] - 2020-05-08
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(openssl tls) (openssl < 1.1) logic inversion - crypto locking callback are not registered properly
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.7] - 2020-05-08
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cmake) default TLS back to mbedtls on Windows Universal Platform
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.6] - 2020-05-06
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cobra bots) add a --heartbeat_timeout option to specify when the bot should terminate because no events are received
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.5] - 2020-05-06
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(openssl tls) when OpenSSL is older than 1.1, register the crypto locking callback to be thread safe. Should fix lots of CI failures
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.4] - 2020-05-04
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cobra bots) do not use a queue to store messages pending processing, let the bot handle queuing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.3] - 2020-04-29
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(http client) better current request cancellation support when the HttpClient destructor is invoked (see #189)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.2] - 2020-04-27
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cmake) fix cmake broken tls option parsing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.1] - 2020-04-27
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(http client) Set default values for most HttpRequestArgs struct members (fix #185)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.5.0] - 2020-04-25
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ssl) Default to OpenSSL on Windows, since it can load the system certificates by default
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.4.1] - 2020-04-25
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(header) Add a space between header name and header value since most http parsers expects it, although it it not required. Cf #184 and #155
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.4.0] - 2020-04-24
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ssl) Add support for supplying SSL CA from memory, for OpenSSL and MbedTLS backends
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.3.3] - 2020-04-17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixbots) display sent/receive message, per seconds as accumulated
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.3.2] - 2020-04-17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ws) add a --logfile option to configure all logs to go to a file
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.3.1] - 2020-04-16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(cobra bots) add a utility class to factor out the common bots features (heartbeat) and move all bots to used it + convert cobra_subscribe to be a bot and add a unittest for it
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.3.0] - 2020-04-15
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(websocket) add a positive number to the heartbeat message sent, incremented each time the heartbeat is sent
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.9] - 2020-04-15
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixcobra) change cobra event callback to use a struct instead of several objects, which is more flexible/extensible
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.8] - 2020-04-15
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixcobra) make CobraConnection_EventType an enum class (CobraEventType)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.7] - 2020-04-14
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixsentry) add a library method to upload a payload directly to sentry
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.6] - 2020-04-14
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ixcobra) snake server / handle invalid incoming json messages + cobra subscriber in fluentd mode insert a created_at timestamp entry
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.5] - 2020-04-13
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(websocket) WebSocketMessagePtr is a unique_ptr instead of a shared_ptr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.4] - 2020-04-13
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(websocket) use persistent member variable as temp variables to encode/decode zlib messages in order to reduce transient allocations
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.3] - 2020-04-13
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(ws) add a --runtime option to ws cobra_subscribe to optionally limit how much time it will run
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.2] - 2020-04-04
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(third_party deps) fix #177, update bundled spdlog to 1.6.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.1] - 2020-04-04
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(windows) when using OpenSSL, the system store is used to populate the cacert. No need to ship a cacert.pem file with your app.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## [9.2.0] - 2020-04-04
 | 
					## [9.2.0] - 2020-04-04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(windows) ci: windows build with TLS (mbedtls) + verify that we can be build with OpenSSL
 | 
					(windows) ci: windows build with TLS (mbedtls) + verify that we can be build with OpenSSL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,10 @@ There is a unittest which can be executed by typing `make test`.
 | 
				
			|||||||
Options for building:
 | 
					Options for building:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `-DUSE_TLS=1` will enable TLS support
 | 
					* `-DUSE_TLS=1` will enable TLS support
 | 
				
			||||||
* `-DUSE_OPEN_SSL=1` will use [openssl](https://www.openssl.org/) for the TLS support (default on Linux and Windows)
 | 
					* `-DUSE_MBED_TLS=1` will use [mbedlts](https://tls.mbed.org/) for the TLS support (default on Windows)
 | 
				
			||||||
* `-DUSE_MBED_TLS=1` will use [mbedlts](https://tls.mbed.org/) for the TLS support
 | 
					 | 
				
			||||||
* `-DUSE_WS=1` will build the ws interactive command line tool
 | 
					* `-DUSE_WS=1` will build the ws interactive command line tool
 | 
				
			||||||
* `-DUSE_TEST=1` will build the unittest
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you are on Windows, look at the [appveyor](https://github.com/machinezone/IXWebSocket/blob/master/appveyor.yml) file (not maintained much though) or rather the [github actions](https://github.com/machinezone/IXWebSocket/blob/master/.github/workflows/ccpp.yml#L40) which have instructions for building dependencies.
 | 
					If you are on Windows, look at the [appveyor](https://github.com/machinezone/IXWebSocket/blob/master/appveyor.yml) file that has instructions for building dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
It is also possible to externally include the project, so that everything is fetched over the wire when you build like so:
 | 
					It is also possible to externally include the project, so that everything is fetched over the wire when you build like so:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,7 +59,7 @@ Note that the version listed here might not be the latest one. See Bintray or th
 | 
				
			|||||||
There is a Dockerfile for running the unittest on Linux, and to run the `ws` tool. It is also available on the docker registry.
 | 
					There is a Dockerfile for running the unittest on Linux, and to run the `ws` tool. It is also available on the docker registry.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
docker run docker.pkg.github.com/machinezone/ixwebsocket/ws:latest --help
 | 
					docker run bsergean/ws
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To use docker-compose you must make a docker container first.
 | 
					To use docker-compose you must make a docker container first.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,8 @@ The regression test is running after each commit on github actions for multiple
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Limitations
 | 
					## Limitations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* On some configuration (mostly Android) certificate validation needs to be setup so that SocketTLSOptions.caFile point to a pem file, such as the one distributed by Firefox. Unless that setup is done connecting to a wss endpoint will display an error. With mbedtls the message will contain `error in handshake : X509 - Certificate verification failed, e.g. CRL, CA or signature check failed`.
 | 
					* On Android, or when using MbedTLS certificate validation needs to be setup so that SocketTLSOptions.caFile point to a pem file, such as the one distributed by [Firefox](https://curl.haxx.se/docs/caextract.html). Unless that setup is done connecting to a wss endpoint will display an error. On Windows with mbedtls the message will contain `error in handshake : X509 - Certificate verification failed, e.g. CRL, CA or signature check failed`.
 | 
				
			||||||
 | 
					* There is no convenient way to embed a ca cert.
 | 
				
			||||||
* Automatic reconnection works at the TCP socket level, and will detect remote end disconnects. However, if the device/computer network become unreachable (by turning off wifi), it is quite hard to reliably and timely detect it at the socket level using `recv` and `send` error codes. [Here](https://stackoverflow.com/questions/14782143/linux-socket-how-to-detect-disconnected-network-in-a-client-program) is a good discussion on the subject. This behavior is consistent with other runtimes such as node.js. One way to detect a disconnected device with low level C code is to do a name resolution with DNS but this can be expensive. Mobile devices have good and reliable API to do that.
 | 
					* Automatic reconnection works at the TCP socket level, and will detect remote end disconnects. However, if the device/computer network become unreachable (by turning off wifi), it is quite hard to reliably and timely detect it at the socket level using `recv` and `send` error codes. [Here](https://stackoverflow.com/questions/14782143/linux-socket-how-to-detect-disconnected-network-in-a-client-program) is a good discussion on the subject. This behavior is consistent with other runtimes such as node.js. One way to detect a disconnected device with low level C code is to do a name resolution with DNS but this can be expensive. Mobile devices have good and reliable API to do that.
 | 
				
			||||||
* The server code is using select to detect incoming data, and creates one OS thread per connection. This is not as scalable as strategies using epoll or kqueue.
 | 
					* The server code is using select to detect incoming data, and creates one OS thread per connection. This is not as scalable as strategies using epoll or kqueue.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -447,7 +447,7 @@ Additional TLS options can be configured by passing a `ix::SocketTLSOptions` ins
 | 
				
			|||||||
webSocket.setTLSOptions({
 | 
					webSocket.setTLSOptions({
 | 
				
			||||||
    .certFile = "path/to/cert/file.pem",
 | 
					    .certFile = "path/to/cert/file.pem",
 | 
				
			||||||
    .keyFile = "path/to/key/file.pem",
 | 
					    .keyFile = "path/to/key/file.pem",
 | 
				
			||||||
    .caFile = "path/to/trust/bundle/file.pem", // as a file, or in memory buffer in PEM format
 | 
					    .caFile = "path/to/trust/bundle/file.pem",
 | 
				
			||||||
    .tls = true // required in server mode
 | 
					    .tls = true // required in server mode
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@@ -461,7 +461,6 @@ On a server, this is necessary for TLS support.
 | 
				
			|||||||
Specifying `caFile` configures the trusted roots bundle file (in PEM format) that will be used to verify peer certificates.
 | 
					Specifying `caFile` configures the trusted roots bundle file (in PEM format) that will be used to verify peer certificates.
 | 
				
			||||||
 - The special value of `SYSTEM` (the default) indicates that the system-configured trust bundle should be used; this is generally what you want when connecting to any publicly exposed API/server.
 | 
					 - The special value of `SYSTEM` (the default) indicates that the system-configured trust bundle should be used; this is generally what you want when connecting to any publicly exposed API/server.
 | 
				
			||||||
 - The special value of `NONE` can be used to disable peer verification; this is only recommended to rule out certificate verification when testing connectivity.
 | 
					 - The special value of `NONE` can be used to disable peer verification; this is only recommended to rule out certificate verification when testing connectivity.
 | 
				
			||||||
 - If the value contain the special value `-----BEGIN CERTIFICATE-----`, the value will be read from memory, and not from a file. This is convenient on platforms like Android where reading / writing to the file system can be challenging without proper permissions, or without knowing the location of a temp directory.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
For a client, specifying `caFile` can be used if connecting to a server that uses a self-signed cert, or when using a custom CA in an internal environment.
 | 
					For a client, specifying `caFile` can be used if connecting to a server that uses a self-signed cert, or when using a custom CA in an internal environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,19 +4,16 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set (IXBOTS_SOURCES
 | 
					set (IXBOTS_SOURCES
 | 
				
			||||||
    ixbots/IXCobraBot.cpp
 | 
					 | 
				
			||||||
    ixbots/IXCobraToSentryBot.cpp
 | 
					    ixbots/IXCobraToSentryBot.cpp
 | 
				
			||||||
    ixbots/IXCobraToStatsdBot.cpp
 | 
					    ixbots/IXCobraToStatsdBot.cpp
 | 
				
			||||||
    ixbots/IXCobraToStdoutBot.cpp
 | 
					    ixbots/IXQueueManager.cpp
 | 
				
			||||||
    ixbots/IXStatsdClient.cpp
 | 
					    ixbots/IXStatsdClient.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set (IXBOTS_HEADERS
 | 
					set (IXBOTS_HEADERS
 | 
				
			||||||
    ixbots/IXCobraBot.h
 | 
					 | 
				
			||||||
    ixbots/IXCobraBotConfig.h
 | 
					 | 
				
			||||||
    ixbots/IXCobraToSentryBot.h
 | 
					    ixbots/IXCobraToSentryBot.h
 | 
				
			||||||
    ixbots/IXCobraToStatsdBot.h
 | 
					    ixbots/IXCobraToStatsdBot.h
 | 
				
			||||||
    ixbots/IXCobraToStdoutBot.h
 | 
					    ixbots/IXQueueManager.h
 | 
				
			||||||
    ixbots/IXStatsdClient.h
 | 
					    ixbots/IXStatsdClient.h
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,6 +27,11 @@ if (NOT JSONCPP_FOUND)
 | 
				
			|||||||
  set(JSONCPP_INCLUDE_DIRS ../third_party/jsoncpp)
 | 
					  set(JSONCPP_INCLUDE_DIRS ../third_party/jsoncpp)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					find_package(SpdLog)
 | 
				
			||||||
 | 
					if (NOT SPDLOG_FOUND)
 | 
				
			||||||
 | 
					  set(SPDLOG_INCLUDE_DIRS ../third_party/spdlog/include)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(IXBOTS_INCLUDE_DIRS
 | 
					set(IXBOTS_INCLUDE_DIRS
 | 
				
			||||||
    .
 | 
					    .
 | 
				
			||||||
    ..
 | 
					    ..
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,268 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraBot.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXCobraBot.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ixcobra/IXCobraConnection.h>
 | 
					 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <chrono>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int64_t CobraBot::run(const CobraBotConfig& botConfig)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto config = botConfig.cobraConfig;
 | 
					 | 
				
			||||||
        auto channel = botConfig.channel;
 | 
					 | 
				
			||||||
        auto filter = botConfig.filter;
 | 
					 | 
				
			||||||
        auto position = botConfig.position;
 | 
					 | 
				
			||||||
        auto enableHeartbeat = botConfig.enableHeartbeat;
 | 
					 | 
				
			||||||
        auto heartBeatTimeout = botConfig.heartBeatTimeout;
 | 
					 | 
				
			||||||
        auto runtime = botConfig.runtime;
 | 
					 | 
				
			||||||
        auto maxEventsPerMinute = botConfig.maxEventsPerMinute;
 | 
					 | 
				
			||||||
        auto limitReceivedEvents = botConfig.limitReceivedEvents;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ix::CobraConnection conn;
 | 
					 | 
				
			||||||
        conn.configure(config);
 | 
					 | 
				
			||||||
        conn.connect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::atomic<uint64_t> sentCount(0);
 | 
					 | 
				
			||||||
        std::atomic<uint64_t> receivedCount(0);
 | 
					 | 
				
			||||||
        uint64_t sentCountTotal(0);
 | 
					 | 
				
			||||||
        uint64_t receivedCountTotal(0);
 | 
					 | 
				
			||||||
        uint64_t sentCountPerSecs(0);
 | 
					 | 
				
			||||||
        uint64_t receivedCountPerSecs(0);
 | 
					 | 
				
			||||||
        std::atomic<int> receivedCountPerMinutes(0);
 | 
					 | 
				
			||||||
        std::atomic<bool> stop(false);
 | 
					 | 
				
			||||||
        std::atomic<bool> throttled(false);
 | 
					 | 
				
			||||||
        std::atomic<bool> fatalCobraError(false);
 | 
					 | 
				
			||||||
        int minuteCounter = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto timer = [&sentCount,
 | 
					 | 
				
			||||||
                      &receivedCount,
 | 
					 | 
				
			||||||
                      &sentCountTotal,
 | 
					 | 
				
			||||||
                      &receivedCountTotal,
 | 
					 | 
				
			||||||
                      &sentCountPerSecs,
 | 
					 | 
				
			||||||
                      &receivedCountPerSecs,
 | 
					 | 
				
			||||||
                      &receivedCountPerMinutes,
 | 
					 | 
				
			||||||
                      &minuteCounter,
 | 
					 | 
				
			||||||
                      &stop] {
 | 
					 | 
				
			||||||
            while (!stop)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                //
 | 
					 | 
				
			||||||
                // We cannot write to sentCount and receivedCount
 | 
					 | 
				
			||||||
                // as those are used externally, so we need to introduce
 | 
					 | 
				
			||||||
                // our own counters
 | 
					 | 
				
			||||||
                //
 | 
					 | 
				
			||||||
                std::stringstream ss;
 | 
					 | 
				
			||||||
                ss << "messages received "
 | 
					 | 
				
			||||||
                   << receivedCountPerSecs
 | 
					 | 
				
			||||||
                   << " "
 | 
					 | 
				
			||||||
                   << receivedCountTotal
 | 
					 | 
				
			||||||
                   << " sent " 
 | 
					 | 
				
			||||||
                   << sentCountPerSecs
 | 
					 | 
				
			||||||
                   << " "
 | 
					 | 
				
			||||||
                   << sentCountTotal;
 | 
					 | 
				
			||||||
                CoreLogger::info(ss.str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                receivedCountPerSecs = receivedCount - receivedCountTotal;
 | 
					 | 
				
			||||||
                sentCountPerSecs = sentCount - sentCountTotal;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                receivedCountTotal += receivedCountPerSecs;
 | 
					 | 
				
			||||||
                sentCountTotal += sentCountPerSecs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                auto duration = std::chrono::seconds(1);
 | 
					 | 
				
			||||||
                std::this_thread::sleep_for(duration);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (minuteCounter++ == 60)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    receivedCountPerMinutes = 0;
 | 
					 | 
				
			||||||
                    minuteCounter = 0;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CoreLogger::info("timer thread done");
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::thread t1(timer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto heartbeat = [&sentCount, &receivedCount, &stop, &enableHeartbeat, &heartBeatTimeout, &fatalCobraError] {
 | 
					 | 
				
			||||||
            std::string state("na");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!enableHeartbeat) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while (!stop)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                std::stringstream ss;
 | 
					 | 
				
			||||||
                ss << "messages received " << receivedCount;
 | 
					 | 
				
			||||||
                ss << "messages sent " << sentCount;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                std::string currentState = ss.str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (currentState == state)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    CoreLogger::error("no messages received or sent for 1 minute, exiting");
 | 
					 | 
				
			||||||
                    fatalCobraError = true;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                state = currentState;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                auto duration = std::chrono::seconds(heartBeatTimeout);
 | 
					 | 
				
			||||||
                std::this_thread::sleep_for(duration);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CoreLogger::info("heartbeat thread done");
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::thread t2(heartbeat);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string subscriptionPosition(position);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        conn.setEventCallback([this,
 | 
					 | 
				
			||||||
                               &conn,
 | 
					 | 
				
			||||||
                               &channel,
 | 
					 | 
				
			||||||
                               &filter,
 | 
					 | 
				
			||||||
                               &subscriptionPosition,
 | 
					 | 
				
			||||||
                               &throttled,
 | 
					 | 
				
			||||||
                               &receivedCount,
 | 
					 | 
				
			||||||
                               &receivedCountPerMinutes,
 | 
					 | 
				
			||||||
                               maxEventsPerMinute,
 | 
					 | 
				
			||||||
                               limitReceivedEvents,
 | 
					 | 
				
			||||||
                               &fatalCobraError,
 | 
					 | 
				
			||||||
                               &sentCount](const CobraEventPtr& event) {
 | 
					 | 
				
			||||||
            if (event->type == ix::CobraEventType::Open)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscriber connected");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for (auto&& it : event->headers)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    CoreLogger::info(it.first + "::" + it.second);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Closed)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscriber closed: {}" + event->errMsg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Authenticated)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscriber authenticated");
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscribing to " + channel);
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscribing at position " + subscriptionPosition);
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscribing with filter " + filter);
 | 
					 | 
				
			||||||
                conn.subscribe(channel, filter, subscriptionPosition,
 | 
					 | 
				
			||||||
                    [&sentCount, &receivedCountPerMinutes,
 | 
					 | 
				
			||||||
                     maxEventsPerMinute, limitReceivedEvents,
 | 
					 | 
				
			||||||
                     &throttled, &receivedCount,
 | 
					 | 
				
			||||||
                     &subscriptionPosition, &fatalCobraError,
 | 
					 | 
				
			||||||
                     this](const Json::Value& msg, const std::string& position) {
 | 
					 | 
				
			||||||
                        subscriptionPosition = position;
 | 
					 | 
				
			||||||
                        ++receivedCount;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        ++receivedCountPerMinutes;
 | 
					 | 
				
			||||||
                        if (limitReceivedEvents)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            if (receivedCountPerMinutes > maxEventsPerMinute)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                return;
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // If we cannot send to sentry fast enough, drop the message
 | 
					 | 
				
			||||||
                        if (throttled)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            return;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        _onBotMessageCallback(
 | 
					 | 
				
			||||||
                            msg, position, throttled,
 | 
					 | 
				
			||||||
                            fatalCobraError, sentCount);
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Subscribed)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscriber: subscribed to channel " + event->subscriptionId);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::UnSubscribed)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::info("Subscriber: unsubscribed from channel " + event->subscriptionId);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Error)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::error("Subscriber: error " + event->errMsg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Published)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::error("Published message hacked: " + std::to_string(event->msgId));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Pong)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::info("Received websocket pong: " + event->errMsg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::HandshakeError)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::error("Subscriber: Handshake error: " + event->errMsg);
 | 
					 | 
				
			||||||
                fatalCobraError = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::AuthenticationError)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::error("Subscriber: Authentication error: " + event->errMsg);
 | 
					 | 
				
			||||||
                fatalCobraError = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::SubscriptionError)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                CoreLogger::error("Subscriber: Subscription error: " + event->errMsg);
 | 
					 | 
				
			||||||
                fatalCobraError = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Run forever
 | 
					 | 
				
			||||||
        if (runtime == -1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            while (true)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                auto duration = std::chrono::seconds(1);
 | 
					 | 
				
			||||||
                std::this_thread::sleep_for(duration);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (fatalCobraError) break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // Run for a duration, used by unittesting now
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            for (int i = 0; i < runtime; ++i)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                auto duration = std::chrono::seconds(1);
 | 
					 | 
				
			||||||
                std::this_thread::sleep_for(duration);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (fatalCobraError) break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // Cleanup.
 | 
					 | 
				
			||||||
        // join all the bg threads and stop them.
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        conn.disconnect();
 | 
					 | 
				
			||||||
        stop = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // progress thread
 | 
					 | 
				
			||||||
        t1.join();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // heartbeat thread
 | 
					 | 
				
			||||||
        if (t2.joinable()) t2.join();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return fatalCobraError ? -1 : (int64_t) sentCount;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void CobraBot::setOnBotMessageCallback(const OnBotMessageCallback& callback)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _onBotMessageCallback = callback;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraBot.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include "IXCobraBotConfig.h"
 | 
					 | 
				
			||||||
#include <json/json.h>
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using OnBotMessageCallback = std::function<void(const Json::Value&,
 | 
					 | 
				
			||||||
                                                    const std::string&,
 | 
					 | 
				
			||||||
                                                    std::atomic<bool>&,
 | 
					 | 
				
			||||||
                                                    std::atomic<bool>&,
 | 
					 | 
				
			||||||
                                                    std::atomic<uint64_t>&)>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class CobraBot
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        CobraBot() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int64_t run(const CobraBotConfig& botConfig);
 | 
					 | 
				
			||||||
        void setOnBotMessageCallback(const OnBotMessageCallback& callback);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
        OnBotMessageCallback _onBotMessageCallback;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraBotConfig.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <limits>
 | 
					 | 
				
			||||||
#include <ixcobra/IXCobraConfig.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef max
 | 
					 | 
				
			||||||
#undef max
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct CobraBotConfig
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        CobraConfig cobraConfig;
 | 
					 | 
				
			||||||
        std::string channel;
 | 
					 | 
				
			||||||
        std::string filter;
 | 
					 | 
				
			||||||
        std::string position = std::string("$");
 | 
					 | 
				
			||||||
        bool enableHeartbeat = true;
 | 
					 | 
				
			||||||
        int heartBeatTimeout = 60;
 | 
					 | 
				
			||||||
        int runtime = -1;
 | 
					 | 
				
			||||||
        int maxEventsPerMinute = std::numeric_limits<int>::max();
 | 
					 | 
				
			||||||
        bool limitReceivedEvents = false;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
@@ -5,43 +5,132 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCobraToSentryBot.h"
 | 
					#include "IXCobraToSentryBot.h"
 | 
				
			||||||
 | 
					#include "IXQueueManager.h"
 | 
				
			||||||
#include "IXCobraBot.h"
 | 
					 | 
				
			||||||
#include <ixcobra/IXCobraConnection.h>
 | 
					 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <ixcobra/IXCobraConnection.h>
 | 
				
			||||||
 | 
					#include <spdlog/spdlog.h>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t cobra_to_sentry_bot(const CobraBotConfig& config,
 | 
					    int cobra_to_sentry_bot(const CobraConfig& config,
 | 
				
			||||||
 | 
					                            const std::string& channel,
 | 
				
			||||||
 | 
					                            const std::string& filter,
 | 
				
			||||||
 | 
					                            const std::string& position,
 | 
				
			||||||
                            SentryClient& sentryClient,
 | 
					                            SentryClient& sentryClient,
 | 
				
			||||||
                                bool verbose)
 | 
					                            bool verbose,
 | 
				
			||||||
 | 
					                            bool strict,
 | 
				
			||||||
 | 
					                            size_t maxQueueSize,
 | 
				
			||||||
 | 
					                            bool enableHeartbeat,
 | 
				
			||||||
 | 
					                            int runtime)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        CobraBot bot;
 | 
					        ix::CobraConnection conn;
 | 
				
			||||||
        bot.setOnBotMessageCallback([&sentryClient, &verbose](const Json::Value& msg,
 | 
					        conn.configure(config);
 | 
				
			||||||
                                                    const std::string& /*position*/,
 | 
					        conn.connect();
 | 
				
			||||||
                                                    std::atomic<bool>& throttled,
 | 
					
 | 
				
			||||||
                                                    std::atomic<bool>& /*fatalCobraError*/,
 | 
					        Json::FastWriter jsonWriter;
 | 
				
			||||||
                                                    std::atomic<uint64_t>& sentCount) -> void {
 | 
					        std::atomic<uint64_t> sentCount(0);
 | 
				
			||||||
            sentryClient.send(msg, verbose,
 | 
					        std::atomic<uint64_t> receivedCount(0);
 | 
				
			||||||
                [&sentCount, &throttled](const HttpResponsePtr& response) {
 | 
					        std::atomic<bool> errorSending(false);
 | 
				
			||||||
                if (!response)
 | 
					        std::atomic<bool> stop(false);
 | 
				
			||||||
 | 
					        std::atomic<bool> throttled(false);
 | 
				
			||||||
 | 
					        std::atomic<bool> fatalCobraError(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        QueueManager queueManager(maxQueueSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto timer = [&sentCount, &receivedCount, &stop] {
 | 
				
			||||||
 | 
					            while (!stop)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                    CoreLogger::warn("Null HTTP Response");
 | 
					                spdlog::info("messages received {} sent {}", receivedCount, sentCount);
 | 
				
			||||||
                    return;
 | 
					
 | 
				
			||||||
 | 
					                auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (response->statusCode == 200)
 | 
					            spdlog::info("timer thread done");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::thread t1(timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto heartbeat = [&sentCount, &receivedCount, &stop, &enableHeartbeat] {
 | 
				
			||||||
 | 
					            std::string state("na");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!enableHeartbeat) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (!stop)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                    sentCount++;
 | 
					                std::stringstream ss;
 | 
				
			||||||
 | 
					                ss << "messages received " << receivedCount;
 | 
				
			||||||
 | 
					                ss << "messages sent " << sentCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                std::string currentState = ss.str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (currentState == state)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("no messages received or sent for 1 minute, exiting");
 | 
				
			||||||
 | 
					                    exit(1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                state = currentState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                auto duration = std::chrono::minutes(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            spdlog::info("heartbeat thread done");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::thread t2(heartbeat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto sentrySender =
 | 
				
			||||||
 | 
					            [&queueManager, verbose, &errorSending, &sentCount, &stop, &throttled, &sentryClient] {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                while (true)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    CoreLogger::error("Error sending data to sentry: " + std::to_string(response->statusCode));
 | 
					                    Json::Value msg = queueManager.pop();
 | 
				
			||||||
                    CoreLogger::error("Response: " + response->payload);
 | 
					
 | 
				
			||||||
 | 
					                    if (stop) break;
 | 
				
			||||||
 | 
					                    if (msg.isNull()) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    auto ret = sentryClient.send(msg, verbose);
 | 
				
			||||||
 | 
					                    HttpResponsePtr response = ret.first;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (!response)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        spdlog::warn("Null HTTP Response");
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (verbose)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        for (auto it : response->headers)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            spdlog::info("{}: {}", it.first, it.second);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        spdlog::info("Upload size: {}", response->uploadSize);
 | 
				
			||||||
 | 
					                        spdlog::info("Download size: {}", response->downloadSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        spdlog::info("Status: {}", response->statusCode);
 | 
				
			||||||
 | 
					                        if (response->errorCode != HttpErrorCode::Ok)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            spdlog::info("error message: {}", response->errorMsg);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (response->headers["Content-Type"] != "application/octet-stream")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            spdlog::info("payload: {}", response->payload);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (response->statusCode != 200)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        spdlog::error("Error sending data to sentry: {}", response->statusCode);
 | 
				
			||||||
 | 
					                        spdlog::error("Body: {}", ret.second);
 | 
				
			||||||
 | 
					                        spdlog::error("Response: {}", response->payload);
 | 
				
			||||||
 | 
					                        errorSending = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        // Error 429 Too Many Requests
 | 
					                        // Error 429 Too Many Requests
 | 
				
			||||||
                        if (response->statusCode == 429)
 | 
					                        if (response->statusCode == 429)
 | 
				
			||||||
@@ -55,12 +144,14 @@ namespace ix
 | 
				
			|||||||
                            if (!ss.eof() || ss.fail())
 | 
					                            if (!ss.eof() || ss.fail())
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                seconds = 30;
 | 
					                                seconds = 30;
 | 
				
			||||||
                            CoreLogger::warn("Error parsing Retry-After header. "
 | 
					                                spdlog::warn("Error parsing Retry-After header. "
 | 
				
			||||||
                                             "Using " + retryAfter + " for the sleep duration");
 | 
					                                             "Using {} for the sleep duration",
 | 
				
			||||||
 | 
					                                             seconds);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        CoreLogger::warn("Error 429 - Too Many Requests. ws will sleep "
 | 
					                            spdlog::warn("Error 429 - Too Many Requests. ws will sleep "
 | 
				
			||||||
                                         "and retry after " + retryAfter + " seconds");
 | 
					                                         "and retry after {} seconds",
 | 
				
			||||||
 | 
					                                         retryAfter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            throttled = true;
 | 
					                            throttled = true;
 | 
				
			||||||
                            auto duration = std::chrono::seconds(seconds);
 | 
					                            auto duration = std::chrono::seconds(seconds);
 | 
				
			||||||
@@ -68,9 +159,147 @@ namespace ix
 | 
				
			|||||||
                            throttled = false;
 | 
					                            throttled = false;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        ++sentCount;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (stop) break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                spdlog::info("sentrySender thread done");
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::thread t3(sentrySender);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn.setEventCallback([&conn,
 | 
				
			||||||
 | 
					                               &channel,
 | 
				
			||||||
 | 
					                               &filter,
 | 
				
			||||||
 | 
					                               &position,
 | 
				
			||||||
 | 
					                               &jsonWriter,
 | 
				
			||||||
 | 
					                               verbose,
 | 
				
			||||||
 | 
					                               &throttled,
 | 
				
			||||||
 | 
					                               &receivedCount,
 | 
				
			||||||
 | 
					                               &fatalCobraError,
 | 
				
			||||||
 | 
					                               &queueManager](ix::CobraConnectionEventType eventType,
 | 
				
			||||||
 | 
					                                              const std::string& errMsg,
 | 
				
			||||||
 | 
					                                              const ix::WebSocketHttpHeaders& headers,
 | 
				
			||||||
 | 
					                                              const std::string& subscriptionId,
 | 
				
			||||||
 | 
					                                              CobraConnection::MsgId msgId) {
 | 
				
			||||||
 | 
					            if (eventType == ix::CobraConnection_EventType_Open)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("Subscriber connected");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (auto it : headers)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("{}: {}", it.first, it.second);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (eventType == ix::CobraConnection_EventType_Closed)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("Subscriber closed");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Authenticated)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("Subscriber authenticated");
 | 
				
			||||||
 | 
					                conn.subscribe(channel,
 | 
				
			||||||
 | 
					                               filter,
 | 
				
			||||||
 | 
					                               position,
 | 
				
			||||||
 | 
					                               [&jsonWriter, verbose, &throttled, &receivedCount, &queueManager](
 | 
				
			||||||
 | 
					                                   const Json::Value& msg, const std::string& position) {
 | 
				
			||||||
 | 
					                                   if (verbose)
 | 
				
			||||||
 | 
					                                   {
 | 
				
			||||||
 | 
					                                       spdlog::info("Subscriber received message {} -> {}", position, jsonWriter.write(msg));
 | 
				
			||||||
 | 
					                                   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                   // If we cannot send to sentry fast enough, drop the message
 | 
				
			||||||
 | 
					                                   if (throttled)
 | 
				
			||||||
 | 
					                                   {
 | 
				
			||||||
 | 
					                                       return;
 | 
				
			||||||
 | 
					                                   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                   ++receivedCount;
 | 
				
			||||||
 | 
					                                   queueManager.add(msg);
 | 
				
			||||||
                               });
 | 
					                               });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Subscribed)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Error)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::error("Subscriber: error {}", errMsg);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Published)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::error("Published message hacked: {}", msgId);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Pong)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("Received websocket pong");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Handshake_Error)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::error("Subscriber: Handshake error: {}", errMsg);
 | 
				
			||||||
 | 
					                fatalCobraError = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Authentication_Error)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::error("Subscriber: Authentication error: {}", errMsg);
 | 
				
			||||||
 | 
					                fatalCobraError = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (eventType == ix::CobraConnection_EventType_Subscription_Error)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::error("Subscriber: Subscription error: {}", errMsg);
 | 
				
			||||||
 | 
					                fatalCobraError = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return bot.run(config);
 | 
					        // Run forever
 | 
				
			||||||
 | 
					        if (runtime == -1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (true)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (strict && errorSending) break;
 | 
				
			||||||
 | 
					                if (fatalCobraError) break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Run for a duration, used by unittesting now
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0 ; i < runtime; ++i)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (strict && errorSending) break;
 | 
				
			||||||
 | 
					                if (fatalCobraError) break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // Cleanup.
 | 
				
			||||||
 | 
					        // join all the bg threads and stop them.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        conn.disconnect();
 | 
				
			||||||
 | 
					        stop = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // progress thread
 | 
				
			||||||
 | 
					        t1.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // heartbeat thread
 | 
				
			||||||
 | 
					        if (t2.joinable()) t2.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // sentry sender thread
 | 
				
			||||||
 | 
					        t3.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ((strict && errorSending) || fatalCobraError) ? -1 : (int) sentCount;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,14 +5,20 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cstdint>
 | 
					#include <ixcobra/IXCobraConfig.h>
 | 
				
			||||||
#include "IXCobraBotConfig.h"
 | 
					 | 
				
			||||||
#include <ixsentry/IXSentryClient.h>
 | 
					#include <ixsentry/IXSentryClient.h>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t cobra_to_sentry_bot(const CobraBotConfig& config,
 | 
					    int cobra_to_sentry_bot(const CobraConfig& config,
 | 
				
			||||||
 | 
					                            const std::string& channel,
 | 
				
			||||||
 | 
					                            const std::string& filter,
 | 
				
			||||||
 | 
					                            const std::string& position,
 | 
				
			||||||
                            SentryClient& sentryClient,
 | 
					                            SentryClient& sentryClient,
 | 
				
			||||||
                                bool verbose);
 | 
					                            bool verbose,
 | 
				
			||||||
 | 
					                            bool strict,
 | 
				
			||||||
 | 
					                            size_t maxQueueSize,
 | 
				
			||||||
 | 
					                            bool enableHeartbeat,
 | 
				
			||||||
 | 
					                            int runtime);
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,16 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCobraToStatsdBot.h"
 | 
					#include "IXCobraToStatsdBot.h"
 | 
				
			||||||
 | 
					#include "IXQueueManager.h"
 | 
				
			||||||
#include "IXCobraBot.h"
 | 
					 | 
				
			||||||
#include "IXStatsdClient.h"
 | 
					#include "IXStatsdClient.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <atomic>
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <condition_variable>
 | 
				
			||||||
#include <ixcobra/IXCobraConnection.h>
 | 
					#include <ixcobra/IXCobraConnection.h>
 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					#include <spdlog/spdlog.h>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -53,22 +56,84 @@ namespace ix
 | 
				
			|||||||
        return val;
 | 
					        return val;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int64_t cobra_to_statsd_bot(const ix::CobraBotConfig& config,
 | 
					    int cobra_to_statsd_bot(const ix::CobraConfig& config,
 | 
				
			||||||
 | 
					                            const std::string& channel,
 | 
				
			||||||
 | 
					                            const std::string& filter,
 | 
				
			||||||
 | 
					                            const std::string& position,
 | 
				
			||||||
                            StatsdClient& statsdClient,
 | 
					                            StatsdClient& statsdClient,
 | 
				
			||||||
                            const std::string& fields,
 | 
					                            const std::string& fields,
 | 
				
			||||||
                            const std::string& gauge,
 | 
					                            const std::string& gauge,
 | 
				
			||||||
                            const std::string& timer,
 | 
					                            const std::string& timer,
 | 
				
			||||||
                                bool verbose)
 | 
					                            bool verbose,
 | 
				
			||||||
 | 
					                            size_t maxQueueSize,
 | 
				
			||||||
 | 
					                            bool enableHeartbeat,
 | 
				
			||||||
 | 
					                            int runtime)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        ix::CobraConnection conn;
 | 
				
			||||||
 | 
					        conn.configure(config);
 | 
				
			||||||
 | 
					        conn.connect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto tokens = parseFields(fields);
 | 
					        auto tokens = parseFields(fields);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CobraBot bot;
 | 
					        Json::FastWriter jsonWriter;
 | 
				
			||||||
        bot.setOnBotMessageCallback(
 | 
					        std::atomic<uint64_t> sentCount(0);
 | 
				
			||||||
            [&statsdClient, &tokens, &gauge, &timer, &verbose](const Json::Value& msg,
 | 
					        std::atomic<uint64_t> receivedCount(0);
 | 
				
			||||||
                                                     const std::string& /*position*/,
 | 
					        std::atomic<bool> stop(false);
 | 
				
			||||||
                                                     std::atomic<bool>& /*throttled*/,
 | 
					        std::atomic<bool> fatalCobraError(false);
 | 
				
			||||||
                                                     std::atomic<bool>& fatalCobraError,
 | 
					
 | 
				
			||||||
                                                     std::atomic<uint64_t>& sentCount) -> void {
 | 
					        QueueManager queueManager(maxQueueSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto progress = [&sentCount, &receivedCount, &stop] {
 | 
				
			||||||
 | 
					            while (!stop)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::info("messages received {} sent {}", receivedCount, sentCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            spdlog::info("timer thread done");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::thread t1(progress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto heartbeat = [&sentCount, &receivedCount, &stop, &enableHeartbeat] {
 | 
				
			||||||
 | 
					            std::string state("na");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!enableHeartbeat) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (!stop)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                std::stringstream ss;
 | 
				
			||||||
 | 
					                ss << "messages received " << receivedCount;
 | 
				
			||||||
 | 
					                ss << "messages sent " << sentCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                std::string currentState = ss.str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (currentState == state)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("no messages received or sent for 1 minute, exiting");
 | 
				
			||||||
 | 
					                    exit(1);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                state = currentState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                auto duration = std::chrono::minutes(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            spdlog::info("heartbeat thread done");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::thread t2(heartbeat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto statsdSender = [&statsdClient, &queueManager, &sentCount, &tokens, &stop, &gauge, &timer, &fatalCobraError, &verbose] {
 | 
				
			||||||
 | 
					            while (true)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Json::Value msg = queueManager.pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (stop) return;
 | 
				
			||||||
 | 
					                if (msg.isNull()) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std::string id;
 | 
					                std::string id;
 | 
				
			||||||
                for (auto&& attr : tokens)
 | 
					                for (auto&& attr : tokens)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -109,14 +174,14 @@ namespace ix
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        CoreLogger::error("Gauge " + gauge + " is not a numeric type");
 | 
					                        spdlog::error("Gauge {} is not a numberic type", gauge);
 | 
				
			||||||
                        fatalCobraError = true;
 | 
					                        fatalCobraError = true;
 | 
				
			||||||
                        return;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (verbose)
 | 
					                    if (verbose)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        CoreLogger::info(id + " - " + attrName + " -> " + std::to_string(x));
 | 
					                        spdlog::info("{} - {} -> {}", id, attrName, x);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!gauge.empty())
 | 
					                    if (!gauge.empty())
 | 
				
			||||||
@@ -129,9 +194,127 @@ namespace ix
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                sentCount++;
 | 
					                sentCount += 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::thread t3(statsdSender);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn.setEventCallback(
 | 
				
			||||||
 | 
					            [&conn, &channel, &filter, &position, &jsonWriter, verbose, &queueManager, &receivedCount, &fatalCobraError](
 | 
				
			||||||
 | 
					                ix::CobraConnectionEventType eventType,
 | 
				
			||||||
 | 
					                const std::string& errMsg,
 | 
				
			||||||
 | 
					                const ix::WebSocketHttpHeaders& headers,
 | 
				
			||||||
 | 
					                const std::string& subscriptionId,
 | 
				
			||||||
 | 
					                CobraConnection::MsgId msgId) {
 | 
				
			||||||
 | 
					                if (eventType == ix::CobraConnection_EventType_Open)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Subscriber connected");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (auto it : headers)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        spdlog::info("{}: {}", it.first, it.second);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (eventType == ix::CobraConnection_EventType_Closed)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Subscriber closed");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Authenticated)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Subscriber authenticated");
 | 
				
			||||||
 | 
					                    conn.subscribe(channel,
 | 
				
			||||||
 | 
					                                   filter,
 | 
				
			||||||
 | 
					                                   position,
 | 
				
			||||||
 | 
					                                   [&jsonWriter, &queueManager, verbose, &receivedCount](
 | 
				
			||||||
 | 
					                                       const Json::Value& msg, const std::string& position) {
 | 
				
			||||||
 | 
					                                       if (verbose)
 | 
				
			||||||
 | 
					                                       {
 | 
				
			||||||
 | 
					                                           spdlog::info("Subscriber received message {} -> {}", position, jsonWriter.write(msg));
 | 
				
			||||||
 | 
					                                       }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                       receivedCount++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                       ++receivedCount;
 | 
				
			||||||
 | 
					                                       queueManager.add(msg);
 | 
				
			||||||
 | 
					                                   });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Subscribed)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Error)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("Subscriber: error {}", errMsg);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Published)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("Published message hacked: {}", msgId);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Pong)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Received websocket pong");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Handshake_Error)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("Subscriber: Handshake error: {}", errMsg);
 | 
				
			||||||
 | 
					                    fatalCobraError = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Authentication_Error)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("Subscriber: Authentication error: {}", errMsg);
 | 
				
			||||||
 | 
					                    fatalCobraError = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (eventType == ix::CobraConnection_EventType_Subscription_Error)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::error("Subscriber: Subscription error: {}", errMsg);
 | 
				
			||||||
 | 
					                    fatalCobraError = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return bot.run(config);
 | 
					        // Run forever
 | 
				
			||||||
 | 
					        if (runtime == -1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (true)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (fatalCobraError) break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Run for a duration, used by unittesting now
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (int i = 0 ; i < runtime; ++i)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (fatalCobraError) break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // Cleanup.
 | 
				
			||||||
 | 
					        // join all the bg threads and stop them.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        conn.disconnect();
 | 
				
			||||||
 | 
					        stop = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // progress thread
 | 
				
			||||||
 | 
					        t1.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // heartbeat thread
 | 
				
			||||||
 | 
					        if (t2.joinable()) t2.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // statsd sender thread
 | 
				
			||||||
 | 
					        t3.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return fatalCobraError ? -1 : (int) sentCount;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,18 +5,23 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cstdint>
 | 
					#include <ixcobra/IXCobraConfig.h>
 | 
				
			||||||
#include <ixbots/IXStatsdClient.h>
 | 
					#include <ixbots/IXStatsdClient.h>
 | 
				
			||||||
#include "IXCobraBotConfig.h"
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t cobra_to_statsd_bot(const ix::CobraBotConfig& config,
 | 
					    int cobra_to_statsd_bot(const ix::CobraConfig& config,
 | 
				
			||||||
 | 
					                            const std::string& channel,
 | 
				
			||||||
 | 
					                            const std::string& filter,
 | 
				
			||||||
 | 
					                            const std::string& position,
 | 
				
			||||||
                            StatsdClient& statsdClient,
 | 
					                            StatsdClient& statsdClient,
 | 
				
			||||||
                            const std::string& fields,
 | 
					                            const std::string& fields,
 | 
				
			||||||
                            const std::string& gauge,
 | 
					                            const std::string& gauge,
 | 
				
			||||||
                            const std::string& timer,
 | 
					                            const std::string& timer,
 | 
				
			||||||
                                bool verbose);
 | 
					                            bool verbose,
 | 
				
			||||||
 | 
					                            size_t maxQueueSize,
 | 
				
			||||||
 | 
					                            bool enableHeartbeat,
 | 
				
			||||||
 | 
					                            int runtime);
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,88 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraToStdoutBot.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXCobraToStdoutBot.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXCobraBot.h"
 | 
					 | 
				
			||||||
#include <chrono>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using StreamWriterPtr = std::unique_ptr<Json::StreamWriter>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    StreamWriterPtr makeStreamWriter()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Json::StreamWriterBuilder builder;
 | 
					 | 
				
			||||||
        builder["commentStyle"] = "None";
 | 
					 | 
				
			||||||
        builder["indentation"] = ""; // will make the JSON object compact
 | 
					 | 
				
			||||||
        std::unique_ptr<Json::StreamWriter> jsonWriter(builder.newStreamWriter());
 | 
					 | 
				
			||||||
        return jsonWriter;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string timeSinceEpoch()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
 | 
					 | 
				
			||||||
        std::chrono::system_clock::duration dtn = tp.time_since_epoch();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::stringstream ss;
 | 
					 | 
				
			||||||
        ss << dtn.count() * std::chrono::system_clock::period::num /
 | 
					 | 
				
			||||||
                  std::chrono::system_clock::period::den;
 | 
					 | 
				
			||||||
        return ss.str();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void writeToStdout(bool fluentd,
 | 
					 | 
				
			||||||
                       const StreamWriterPtr& jsonWriter,
 | 
					 | 
				
			||||||
                       const Json::Value& msg,
 | 
					 | 
				
			||||||
                       const std::string& position)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Json::Value enveloppe;
 | 
					 | 
				
			||||||
        if (fluentd)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            enveloppe["producer"] = "cobra";
 | 
					 | 
				
			||||||
            enveloppe["consumer"] = "fluentd";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Json::Value nestedMessage(msg);
 | 
					 | 
				
			||||||
            nestedMessage["position"] = position;
 | 
					 | 
				
			||||||
            nestedMessage["created_at"] = timeSinceEpoch();
 | 
					 | 
				
			||||||
            enveloppe["message"] = nestedMessage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            jsonWriter->write(enveloppe, &std::cout);
 | 
					 | 
				
			||||||
            std::cout << std::endl; // add lf and flush
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            enveloppe = msg;
 | 
					 | 
				
			||||||
            std::cout << position << " ";
 | 
					 | 
				
			||||||
            jsonWriter->write(enveloppe, &std::cout);
 | 
					 | 
				
			||||||
            std::cout << std::endl;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int64_t cobra_to_stdout_bot(const ix::CobraBotConfig& config,
 | 
					 | 
				
			||||||
                                bool fluentd,
 | 
					 | 
				
			||||||
                                bool quiet)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        CobraBot bot;
 | 
					 | 
				
			||||||
        auto jsonWriter = makeStreamWriter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bot.setOnBotMessageCallback(
 | 
					 | 
				
			||||||
            [&fluentd, &quiet, &jsonWriter](const Json::Value& msg,
 | 
					 | 
				
			||||||
                                            const std::string& position,
 | 
					 | 
				
			||||||
                                            std::atomic<bool>& /*throttled*/,
 | 
					 | 
				
			||||||
                                            std::atomic<bool>& /*fatalCobraError*/,
 | 
					 | 
				
			||||||
                                            std::atomic<uint64_t>& sentCount) -> void {
 | 
					 | 
				
			||||||
                if (!quiet)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    writeToStdout(fluentd, jsonWriter, msg, position);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sentCount++;
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return bot.run(config);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraToStdoutBot.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include "IXCobraBotConfig.h"
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int64_t cobra_to_stdout_bot(const ix::CobraBotConfig& config,
 | 
					 | 
				
			||||||
                                bool fluentd,
 | 
					 | 
				
			||||||
                                bool quiet);
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
							
								
								
									
										66
									
								
								ixbots/ixbots/IXQueueManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								ixbots/ixbots/IXQueueManager.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXQueueManager.cpp
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXQueueManager.h"
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Json::Value QueueManager::pop()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::unique_lock<std::mutex> lock(_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (_queues.empty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Json::Value val;
 | 
				
			||||||
 | 
					            return val;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::vector<std::string> games;
 | 
				
			||||||
 | 
					        for (auto it : _queues)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            games.push_back(it.first);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::random_shuffle(games.begin(), games.end());
 | 
				
			||||||
 | 
					        std::string game = games[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto duration = std::chrono::seconds(1);
 | 
				
			||||||
 | 
					        _condition.wait_for(lock, duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (_queues[game].empty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Json::Value val;
 | 
				
			||||||
 | 
					            return val;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto msg = _queues[game].front();
 | 
				
			||||||
 | 
					        _queues[game].pop();
 | 
				
			||||||
 | 
					        return msg;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void QueueManager::add(Json::Value msg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::unique_lock<std::mutex> lock(_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string game;
 | 
				
			||||||
 | 
					        if (msg.isMember("device") && msg["device"].isMember("game"))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            game = msg["device"]["game"].asString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (game.empty()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // if the sending is not fast enough there is no point
 | 
				
			||||||
 | 
					        // in queuing too many events.
 | 
				
			||||||
 | 
					        if (_queues[game].size() < _maxQueueSize)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _queues[game].push(msg);
 | 
				
			||||||
 | 
					            _condition.notify_one();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								ixbots/ixbots/IXQueueManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								ixbots/ixbots/IXQueueManager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXQueueManager.h
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <json/json.h>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <condition_variable>
 | 
				
			||||||
 | 
					#include <queue>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class QueueManager
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        QueueManager(size_t maxQueueSize)
 | 
				
			||||||
 | 
					            : _maxQueueSize(maxQueueSize)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Json::Value pop();
 | 
				
			||||||
 | 
					        void add(Json::Value msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        std::map<std::string, std::queue<Json::Value>> _queues;
 | 
				
			||||||
 | 
					        std::mutex _mutex;
 | 
				
			||||||
 | 
					        std::condition_variable _condition;
 | 
				
			||||||
 | 
					        size_t _maxQueueSize;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -39,21 +39,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXStatsdClient.h"
 | 
					#include "IXStatsdClient.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXNetSystem.h>
 | 
					#include <ixwebsocket/IXNetSystem.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    StatsdClient::StatsdClient(const std::string& host, int port, const std::string& prefix)
 | 
					    StatsdClient::StatsdClient(const std::string& host,
 | 
				
			||||||
 | 
					                               int port,
 | 
				
			||||||
 | 
					                               const std::string& prefix)
 | 
				
			||||||
    : _host(host)
 | 
					    : _host(host)
 | 
				
			||||||
      , _port(port)
 | 
					      , _port(port)
 | 
				
			||||||
      , _prefix(prefix)
 | 
					      , _prefix(prefix)
 | 
				
			||||||
      , _stop(false)
 | 
					      , _stop(false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _thread = std::thread([this] {
 | 
					        _thread = std::thread([this]
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            while (!_stop)
 | 
					            while (!_stop)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                flushQueue();
 | 
					                flushQueue();
 | 
				
			||||||
@@ -116,8 +119,8 @@ namespace ix
 | 
				
			|||||||
        cleanup(key);
 | 
					        cleanup(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        char buf[256];
 | 
					        char buf[256];
 | 
				
			||||||
        snprintf(
 | 
					        snprintf(buf, sizeof(buf), "%s%s:%zd|%s\n",
 | 
				
			||||||
            buf, sizeof(buf), "%s%s:%zd|%s\n", _prefix.c_str(), key.c_str(), value, type.c_str());
 | 
					                 _prefix.c_str(), key.c_str(), value, type.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        enqueue(buf);
 | 
					        enqueue(buf);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
@@ -139,7 +142,9 @@ namespace ix
 | 
				
			|||||||
            auto ret = _socket.sendto(message);
 | 
					            auto ret = _socket.sendto(message);
 | 
				
			||||||
            if (ret != 0)
 | 
					            if (ret != 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::cerr << "error: " << strerror(UdpSocket::getErrno()) << std::endl;
 | 
					                std::cerr << "error: "
 | 
				
			||||||
 | 
					                          << strerror(UdpSocket::getErrno())
 | 
				
			||||||
 | 
					                          << std::endl;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            _queue.pop_front();
 | 
					            _queue.pop_front();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,20 +6,21 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <deque>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXUdpSocket.h>
 | 
					#include <ixwebsocket/IXUdpSocket.h>
 | 
				
			||||||
#include <mutex>
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
 | 
					#include <deque>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class StatsdClient
 | 
					    class StatsdClient
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        StatsdClient(const std::string& host = "127.0.0.1",
 | 
					        StatsdClient(const std::string& host="127.0.0.1",
 | 
				
			||||||
                     int port = 8125,
 | 
					                     int port=8125,
 | 
				
			||||||
                     const std::string& prefix = "");
 | 
					                     const std::string& prefix = "");
 | 
				
			||||||
        ~StatsdClient();
 | 
					        ~StatsdClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@ set (IXCOBRA_HEADERS
 | 
				
			|||||||
    ixcobra/IXCobraMetricsThreadedPublisher.h
 | 
					    ixcobra/IXCobraMetricsThreadedPublisher.h
 | 
				
			||||||
    ixcobra/IXCobraMetricsPublisher.h
 | 
					    ixcobra/IXCobraMetricsPublisher.h
 | 
				
			||||||
    ixcobra/IXCobraConfig.h
 | 
					    ixcobra/IXCobraConfig.h
 | 
				
			||||||
    ixcobra/IXCobraEventType.h
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_library(ixcobra STATIC
 | 
					add_library(ixcobra STATIC
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocketPerMessageDeflateOptions.h>
 | 
					#include <ixwebsocket/IXWebSocketPerMessageDeflateOptions.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,17 +5,17 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCobraConnection.h"
 | 
					#include "IXCobraConnection.h"
 | 
				
			||||||
 | 
					#include <ixcrypto/IXHMac.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cassert>
 | 
					#include <stdexcept>
 | 
				
			||||||
#include <cmath>
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <ixcrypto/IXHMac.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <stdexcept>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -26,12 +26,12 @@ namespace ix
 | 
				
			|||||||
    constexpr CobraConnection::MsgId CobraConnection::kInvalidMsgId;
 | 
					    constexpr CobraConnection::MsgId CobraConnection::kInvalidMsgId;
 | 
				
			||||||
    constexpr int CobraConnection::kPingIntervalSecs;
 | 
					    constexpr int CobraConnection::kPingIntervalSecs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CobraConnection::CobraConnection()
 | 
					    CobraConnection::CobraConnection() :
 | 
				
			||||||
        : _webSocket(new WebSocket())
 | 
					        _webSocket(new WebSocket()),
 | 
				
			||||||
        , _publishMode(CobraConnection_PublishMode_Immediate)
 | 
					        _publishMode(CobraConnection_PublishMode_Immediate),
 | 
				
			||||||
        , _authenticated(false)
 | 
					        _authenticated(false),
 | 
				
			||||||
        , _eventCallback(nullptr)
 | 
					        _eventCallback(nullptr),
 | 
				
			||||||
        , _id(1)
 | 
					        _id(1)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _pdu["action"] = "rtm/publish";
 | 
					        _pdu["action"] = "rtm/publish";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +87,7 @@ namespace ix
 | 
				
			|||||||
        _eventCallback = eventCallback;
 | 
					        _eventCallback = eventCallback;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CobraConnection::invokeEventCallback(ix::CobraEventType eventType,
 | 
					    void CobraConnection::invokeEventCallback(ix::CobraConnectionEventType eventType,
 | 
				
			||||||
                                              const std::string& errorMsg,
 | 
					                                              const std::string& errorMsg,
 | 
				
			||||||
                                              const WebSocketHttpHeaders& headers,
 | 
					                                              const WebSocketHttpHeaders& headers,
 | 
				
			||||||
                                              const std::string& subscriptionId,
 | 
					                                              const std::string& subscriptionId,
 | 
				
			||||||
@@ -96,8 +96,7 @@ namespace ix
 | 
				
			|||||||
        std::lock_guard<std::mutex> lock(_eventCallbackMutex);
 | 
					        std::lock_guard<std::mutex> lock(_eventCallbackMutex);
 | 
				
			||||||
        if (_eventCallback)
 | 
					        if (_eventCallback)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _eventCallback(
 | 
					            _eventCallback(eventType, errorMsg, headers, subscriptionId, msgId);
 | 
				
			||||||
                std::make_unique<CobraEvent>(eventType, errorMsg, headers, subscriptionId, msgId));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -106,7 +105,7 @@ namespace ix
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << errorMsg << " : received pdu => " << serializedPdu;
 | 
					        ss << errorMsg << " : received pdu => " << serializedPdu;
 | 
				
			||||||
        invokeEventCallback(ix::CobraEventType::Error, ss.str());
 | 
					        invokeEventCallback(ix::CobraConnection_EventType_Error, ss.str());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CobraConnection::disconnect()
 | 
					    void CobraConnection::disconnect()
 | 
				
			||||||
@@ -117,13 +116,17 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void CobraConnection::initWebSocketOnMessageCallback()
 | 
					    void CobraConnection::initWebSocketOnMessageCallback()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _webSocket->setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
 | 
					        _webSocket->setOnMessageCallback(
 | 
				
			||||||
 | 
					            [this](const ix::WebSocketMessagePtr& msg)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                CobraConnection::invokeTrafficTrackerCallback(msg->wireSize, true);
 | 
					                CobraConnection::invokeTrafficTrackerCallback(msg->wireSize, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std::stringstream ss;
 | 
					                std::stringstream ss;
 | 
				
			||||||
                if (msg->type == ix::WebSocketMessageType::Open)
 | 
					                if (msg->type == ix::WebSocketMessageType::Open)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                invokeEventCallback(ix::CobraEventType::Open, std::string(), msg->openInfo.headers);
 | 
					                    invokeEventCallback(ix::CobraConnection_EventType_Open,
 | 
				
			||||||
 | 
					                                        std::string(),
 | 
				
			||||||
 | 
					                                        msg->openInfo.headers);
 | 
				
			||||||
                    sendHandshakeMessage();
 | 
					                    sendHandshakeMessage();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (msg->type == ix::WebSocketMessageType::Close)
 | 
					                else if (msg->type == ix::WebSocketMessageType::Close)
 | 
				
			||||||
@@ -133,7 +136,8 @@ namespace ix
 | 
				
			|||||||
                    std::stringstream ss;
 | 
					                    std::stringstream ss;
 | 
				
			||||||
                    ss << "Close code " << msg->closeInfo.code;
 | 
					                    ss << "Close code " << msg->closeInfo.code;
 | 
				
			||||||
                    ss << " reason " << msg->closeInfo.reason;
 | 
					                    ss << " reason " << msg->closeInfo.reason;
 | 
				
			||||||
                invokeEventCallback(ix::CobraEventType::Closed, ss.str());
 | 
					                    invokeEventCallback(ix::CobraConnection_EventType_Closed,
 | 
				
			||||||
 | 
					                                        ss.str());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (msg->type == ix::WebSocketMessageType::Message)
 | 
					                else if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -157,23 +161,24 @@ namespace ix
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        if (!handleHandshakeResponse(data))
 | 
					                        if (!handleHandshakeResponse(data))
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                        invokeErrorCallback("Error extracting nonce from handshake response",
 | 
					                            invokeErrorCallback("Error extracting nonce from handshake response", msg->str);
 | 
				
			||||||
                                            msg->str);
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (action == "auth/handshake/error")
 | 
					                    else if (action == "auth/handshake/error")
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                    invokeEventCallback(ix::CobraEventType::HandshakeError, msg->str);
 | 
					                        invokeEventCallback(ix::CobraConnection_EventType_Handshake_Error,
 | 
				
			||||||
 | 
					                                            msg->str);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (action == "auth/authenticate/ok")
 | 
					                    else if (action == "auth/authenticate/ok")
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _authenticated = true;
 | 
					                        _authenticated = true;
 | 
				
			||||||
                    invokeEventCallback(ix::CobraEventType::Authenticated);
 | 
					                        invokeEventCallback(ix::CobraConnection_EventType_Authenticated);
 | 
				
			||||||
                        flushQueue();
 | 
					                        flushQueue();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (action == "auth/authenticate/error")
 | 
					                    else if (action == "auth/authenticate/error")
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                    invokeEventCallback(ix::CobraEventType::AuthenticationError, msg->str);
 | 
					                        invokeEventCallback(ix::CobraConnection_EventType_Authentication_Error,
 | 
				
			||||||
 | 
					                                            msg->str);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (action == "rtm/subscription/data")
 | 
					                    else if (action == "rtm/subscription/data")
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -188,7 +193,8 @@ namespace ix
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (action == "rtm/subscribe/error")
 | 
					                    else if (action == "rtm/subscribe/error")
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                    invokeEventCallback(ix::CobraEventType::SubscriptionError, msg->str);
 | 
					                        invokeEventCallback(ix::CobraConnection_EventType_Subscription_Error,
 | 
				
			||||||
 | 
					                                            msg->str);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (action == "rtm/unsubscribe/ok")
 | 
					                    else if (action == "rtm/unsubscribe/ok")
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -228,7 +234,7 @@ namespace ix
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else if (msg->type == ix::WebSocketMessageType::Pong)
 | 
					                else if (msg->type == ix::WebSocketMessageType::Pong)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                invokeEventCallback(ix::CobraEventType::Pong, msg->str);
 | 
					                    invokeEventCallback(ix::CobraConnection_EventType_Pong);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -243,8 +249,7 @@ namespace ix
 | 
				
			|||||||
        return _publishMode;
 | 
					        return _publishMode;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CobraConnection::configure(
 | 
					    void CobraConnection::configure(const std::string& appkey,
 | 
				
			||||||
        const std::string& appkey,
 | 
					 | 
				
			||||||
                                    const std::string& endpoint,
 | 
					                                    const std::string& endpoint,
 | 
				
			||||||
                                    const std::string& rolename,
 | 
					                                    const std::string& rolename,
 | 
				
			||||||
                                    const std::string& rolesecret,
 | 
					                                    const std::string& rolesecret,
 | 
				
			||||||
@@ -391,9 +396,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (!subscriptionId.isString()) return false;
 | 
					        if (!subscriptionId.isString()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        invokeEventCallback(ix::CobraEventType::Subscribed,
 | 
					        invokeEventCallback(ix::CobraConnection_EventType_Subscribed,
 | 
				
			||||||
                            std::string(),
 | 
					                            std::string(), WebSocketHttpHeaders(),
 | 
				
			||||||
                            WebSocketHttpHeaders(),
 | 
					 | 
				
			||||||
                            subscriptionId.asString());
 | 
					                            subscriptionId.asString());
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -410,9 +414,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (!subscriptionId.isString()) return false;
 | 
					        if (!subscriptionId.isString()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        invokeEventCallback(ix::CobraEventType::UnSubscribed,
 | 
					        invokeEventCallback(ix::CobraConnection_EventType_UnSubscribed,
 | 
				
			||||||
                            std::string(),
 | 
					                            std::string(), WebSocketHttpHeaders(),
 | 
				
			||||||
                            WebSocketHttpHeaders(),
 | 
					 | 
				
			||||||
                            subscriptionId.asString());
 | 
					                            subscriptionId.asString());
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -459,11 +462,9 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        uint64_t msgId = id.asUInt64();
 | 
					        uint64_t msgId = id.asUInt64();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        invokeEventCallback(ix::CobraEventType::Published,
 | 
					        invokeEventCallback(ix::CobraConnection_EventType_Published,
 | 
				
			||||||
                            std::string(),
 | 
					                            std::string(), WebSocketHttpHeaders(),
 | 
				
			||||||
                            WebSocketHttpHeaders(),
 | 
					                            std::string(), msgId);
 | 
				
			||||||
                            std::string(),
 | 
					 | 
				
			||||||
                            msgId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        invokePublishTrackerCallback(false, true);
 | 
					        invokePublishTrackerCallback(false, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -493,7 +494,9 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::pair<CobraConnection::MsgId, std::string> CobraConnection::prePublish(
 | 
					    std::pair<CobraConnection::MsgId, std::string> CobraConnection::prePublish(
 | 
				
			||||||
        const Json::Value& channels, const Json::Value& msg, bool addToQueue)
 | 
					        const Json::Value& channels,
 | 
				
			||||||
 | 
					        const Json::Value& msg,
 | 
				
			||||||
 | 
					        bool addToQueue)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_prePublishMutex);
 | 
					        std::lock_guard<std::mutex> lock(_prePublishMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -659,7 +662,8 @@ namespace ix
 | 
				
			|||||||
    bool CobraConnection::publishMessage(const std::string& serializedJson)
 | 
					    bool CobraConnection::publishMessage(const std::string& serializedJson)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto webSocketSendInfo = _webSocket->send(serializedJson);
 | 
					        auto webSocketSendInfo = _webSocket->send(serializedJson);
 | 
				
			||||||
        CobraConnection::invokeTrafficTrackerCallback(webSocketSendInfo.wireSize, false);
 | 
					        CobraConnection::invokeTrafficTrackerCallback(webSocketSendInfo.wireSize,
 | 
				
			||||||
 | 
					                                                      false);
 | 
				
			||||||
        return webSocketSendInfo.success;
 | 
					        return webSocketSendInfo.success;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,19 +6,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCobraConfig.h"
 | 
					 | 
				
			||||||
#include "IXCobraEvent.h"
 | 
					 | 
				
			||||||
#include "IXCobraEventType.h"
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
					#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketPerMessageDeflateOptions.h>
 | 
					#include <ixwebsocket/IXWebSocketPerMessageDeflateOptions.h>
 | 
				
			||||||
#include <json/json.h>
 | 
					#include <json/json.h>
 | 
				
			||||||
#include <limits>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <queue>
 | 
					#include <queue>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					#include <limits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXCobraConfig.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef max
 | 
					#ifdef max
 | 
				
			||||||
#undef max
 | 
					#undef max
 | 
				
			||||||
@@ -29,6 +28,21 @@ namespace ix
 | 
				
			|||||||
    class WebSocket;
 | 
					    class WebSocket;
 | 
				
			||||||
    struct SocketTLSOptions;
 | 
					    struct SocketTLSOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum CobraConnectionEventType
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Authenticated = 0,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Error = 1,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Open = 2,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Closed = 3,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Subscribed = 4,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_UnSubscribed = 5,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Published = 6,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Pong = 7,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Handshake_Error = 8,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Authentication_Error = 9,
 | 
				
			||||||
 | 
					        CobraConnection_EventType_Subscription_Error = 10
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum CobraConnectionPublishMode
 | 
					    enum CobraConnectionPublishMode
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        CobraConnection_PublishMode_Immediate = 0,
 | 
					        CobraConnection_PublishMode_Immediate = 0,
 | 
				
			||||||
@@ -36,7 +50,11 @@ namespace ix
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using SubscriptionCallback = std::function<void(const Json::Value&, const std::string&)>;
 | 
					    using SubscriptionCallback = std::function<void(const Json::Value&, const std::string&)>;
 | 
				
			||||||
    using EventCallback = std::function<void(const CobraEventPtr&)>;
 | 
					    using EventCallback = std::function<void(CobraConnectionEventType,
 | 
				
			||||||
 | 
					                                             const std::string&,
 | 
				
			||||||
 | 
					                                             const WebSocketHttpHeaders&,
 | 
				
			||||||
 | 
					                                             const std::string&,
 | 
				
			||||||
 | 
					                                             uint64_t msgId)>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using TrafficTrackerCallback = std::function<void(size_t size, bool incoming)>;
 | 
					    using TrafficTrackerCallback = std::function<void(size_t size, bool incoming)>;
 | 
				
			||||||
    using PublishTrackerCallback = std::function<void(bool sent, bool acked)>;
 | 
					    using PublishTrackerCallback = std::function<void(bool sent, bool acked)>;
 | 
				
			||||||
@@ -120,7 +138,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /// Prepare a message for transmission
 | 
					        /// Prepare a message for transmission
 | 
				
			||||||
        /// (update the pdu, compute a msgId, serialize json to a string)
 | 
					        /// (update the pdu, compute a msgId, serialize json to a string)
 | 
				
			||||||
        std::pair<CobraConnection::MsgId, std::string> prePublish(const Json::Value& channels,
 | 
					        std::pair<CobraConnection::MsgId, std::string> prePublish(
 | 
				
			||||||
 | 
					            const Json::Value& channels,
 | 
				
			||||||
            const Json::Value& msg,
 | 
					            const Json::Value& msg,
 | 
				
			||||||
            bool addToQueue);
 | 
					            bool addToQueue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,7 +171,7 @@ namespace ix
 | 
				
			|||||||
        static void invokePublishTrackerCallback(bool sent, bool acked);
 | 
					        static void invokePublishTrackerCallback(bool sent, bool acked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Invoke event callbacks
 | 
					        /// Invoke event callbacks
 | 
				
			||||||
        void invokeEventCallback(CobraEventType eventType,
 | 
					        void invokeEventCallback(CobraConnectionEventType eventType,
 | 
				
			||||||
                                 const std::string& errorMsg = std::string(),
 | 
					                                 const std::string& errorMsg = std::string(),
 | 
				
			||||||
                                 const WebSocketHttpHeaders& headers = WebSocketHttpHeaders(),
 | 
					                                 const WebSocketHttpHeaders& headers = WebSocketHttpHeaders(),
 | 
				
			||||||
                                 const std::string& subscriptionId = std::string(),
 | 
					                                 const std::string& subscriptionId = std::string(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,41 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraEvent.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXCobraEventType.h"
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct CobraEvent
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ix::CobraEventType type;
 | 
					 | 
				
			||||||
        const std::string& errMsg;
 | 
					 | 
				
			||||||
        const ix::WebSocketHttpHeaders& headers;
 | 
					 | 
				
			||||||
        const std::string& subscriptionId;
 | 
					 | 
				
			||||||
        uint64_t msgId; // CobraConnection::MsgId
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CobraEvent(ix::CobraEventType t,
 | 
					 | 
				
			||||||
                   const std::string& e,
 | 
					 | 
				
			||||||
                   const ix::WebSocketHttpHeaders& h,
 | 
					 | 
				
			||||||
                   const std::string& s,
 | 
					 | 
				
			||||||
                   uint64_t m)
 | 
					 | 
				
			||||||
            : type(t)
 | 
					 | 
				
			||||||
            , errMsg(e)
 | 
					 | 
				
			||||||
            , headers(h)
 | 
					 | 
				
			||||||
            , subscriptionId(s)
 | 
					 | 
				
			||||||
            , msgId(m)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    using CobraEventPtr = std::unique_ptr<CobraEvent>;
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraEventType.h
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    enum class CobraEventType
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Authenticated = 0,
 | 
					 | 
				
			||||||
        Error = 1,
 | 
					 | 
				
			||||||
        Open = 2,
 | 
					 | 
				
			||||||
        Closed = 3,
 | 
					 | 
				
			||||||
        Subscribed = 4,
 | 
					 | 
				
			||||||
        UnSubscribed = 5,
 | 
					 | 
				
			||||||
        Published = 6,
 | 
					 | 
				
			||||||
        Pong = 7,
 | 
					 | 
				
			||||||
        HandshakeError = 8,
 | 
					 | 
				
			||||||
        AuthenticationError = 9,
 | 
					 | 
				
			||||||
        SubscriptionError = 10
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -5,9 +5,9 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCobraMetricsPublisher.h"
 | 
					#include "IXCobraMetricsPublisher.h"
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
					 | 
				
			||||||
#include <stdexcept>
 | 
					#include <stdexcept>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,8 +17,8 @@ namespace ix
 | 
				
			|||||||
    const std::string CobraMetricsPublisher::kSetRateControlId = "sms_set_rate_control_id";
 | 
					    const std::string CobraMetricsPublisher::kSetRateControlId = "sms_set_rate_control_id";
 | 
				
			||||||
    const std::string CobraMetricsPublisher::kSetBlacklistId = "sms_set_blacklist_id";
 | 
					    const std::string CobraMetricsPublisher::kSetBlacklistId = "sms_set_blacklist_id";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CobraMetricsPublisher::CobraMetricsPublisher()
 | 
					    CobraMetricsPublisher::CobraMetricsPublisher() :
 | 
				
			||||||
        : _enabled(true)
 | 
					        _enabled(true)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,7 +27,8 @@ namespace ix
 | 
				
			|||||||
        ;
 | 
					        ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CobraMetricsPublisher::configure(const CobraConfig& config, const std::string& channel)
 | 
					    void CobraMetricsPublisher::configure(const CobraConfig& config,
 | 
				
			||||||
 | 
					                                          const std::string& channel)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Configure the satori connection and start its publish background thread
 | 
					        // Configure the satori connection and start its publish background thread
 | 
				
			||||||
        _cobra_metrics_theaded_publisher.configure(config, channel);
 | 
					        _cobra_metrics_theaded_publisher.configure(config, channel);
 | 
				
			||||||
@@ -106,7 +107,8 @@ namespace ix
 | 
				
			|||||||
        auto last_update = _last_update.find(id);
 | 
					        auto last_update = _last_update.find(id);
 | 
				
			||||||
        if (last_update == _last_update.end()) return false;
 | 
					        if (last_update == _last_update.end()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto timeDeltaFromLastSend = std::chrono::steady_clock::now() - last_update->second;
 | 
					        auto timeDeltaFromLastSend =
 | 
				
			||||||
 | 
					            std::chrono::steady_clock::now() - last_update->second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return timeDeltaFromLastSend < std::chrono::seconds(rate_control_it->second);
 | 
					        return timeDeltaFromLastSend < std::chrono::seconds(rate_control_it->second);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -121,7 +123,8 @@ namespace ix
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        auto now = std::chrono::system_clock::now();
 | 
					        auto now = std::chrono::system_clock::now();
 | 
				
			||||||
        auto ms =
 | 
					        auto ms =
 | 
				
			||||||
            std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
 | 
					            std::chrono::duration_cast<std::chrono::milliseconds>(
 | 
				
			||||||
 | 
					                now.time_since_epoch()).count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ms;
 | 
					        return ms;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -162,7 +165,8 @@ namespace ix
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CobraConnection::MsgId CobraMetricsPublisher::push(const std::string& id,
 | 
					    CobraConnection::MsgId CobraMetricsPublisher::push(
 | 
				
			||||||
 | 
					        const std::string& id,
 | 
				
			||||||
        const Json::Value& data,
 | 
					        const Json::Value& data,
 | 
				
			||||||
        bool shouldPushTest)
 | 
					        bool shouldPushTest)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /// Configuration / set keys, etc...
 | 
					        /// Configuration / set keys, etc...
 | 
				
			||||||
        /// All input data but the channel name is encrypted with rc4
 | 
					        /// All input data but the channel name is encrypted with rc4
 | 
				
			||||||
        void configure(const CobraConfig& config, const std::string& channel);
 | 
					        void configure(const CobraConfig& config,
 | 
				
			||||||
 | 
					                       const std::string& channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Setter for the list of blacklisted metrics ids.
 | 
					        /// Setter for the list of blacklisted metrics ids.
 | 
				
			||||||
        /// That list is sorted internally for fast lookups
 | 
					        /// That list is sorted internally for fast lookups
 | 
				
			||||||
@@ -67,14 +68,10 @@ namespace ix
 | 
				
			|||||||
        /// shouldPush method for places where we want to be as lightweight as possible when
 | 
					        /// shouldPush method for places where we want to be as lightweight as possible when
 | 
				
			||||||
        /// collecting metrics. When set to false, it is used so that we don't do double work when
 | 
					        /// collecting metrics. When set to false, it is used so that we don't do double work when
 | 
				
			||||||
        /// computing whether a metrics should be sent or not.
 | 
					        /// computing whether a metrics should be sent or not.
 | 
				
			||||||
        CobraConnection::MsgId push(const std::string& id,
 | 
					        CobraConnection::MsgId push(const std::string& id, const Json::Value& data, bool shouldPushTest = true);
 | 
				
			||||||
                                    const Json::Value& data,
 | 
					 | 
				
			||||||
                                    bool shouldPushTest = true);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Interface used by lua. msg is a json encoded string.
 | 
					        /// Interface used by lua. msg is a json encoded string.
 | 
				
			||||||
        CobraConnection::MsgId push(const std::string& id,
 | 
					        CobraConnection::MsgId push(const std::string& id, const std::string& data, bool shouldPushTest = true);
 | 
				
			||||||
                                    const std::string& data,
 | 
					 | 
				
			||||||
                                    bool shouldPushTest = true);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Tells whether a metric can be pushed.
 | 
					        /// Tells whether a metric can be pushed.
 | 
				
			||||||
        /// A metric can be pushed if it satisfies those conditions:
 | 
					        /// A metric can be pushed if it satisfies those conditions:
 | 
				
			||||||
@@ -92,16 +89,10 @@ namespace ix
 | 
				
			|||||||
        void setGenericAttributes(const std::string& attrName, const Json::Value& value);
 | 
					        void setGenericAttributes(const std::string& attrName, const Json::Value& value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Set a unique id for the session. A uuid can be used.
 | 
					        /// Set a unique id for the session. A uuid can be used.
 | 
				
			||||||
        void setSession(const std::string& session)
 | 
					        void setSession(const std::string& session) { _session = session; }
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _session = session;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Get the unique id used to identify the current session
 | 
					        /// Get the unique id used to identify the current session
 | 
				
			||||||
        const std::string& getSession() const
 | 
					        const std::string& getSession() const { return _session; }
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return _session;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Return the number of milliseconds since the epoch (~1970)
 | 
					        /// Return the number of milliseconds since the epoch (~1970)
 | 
				
			||||||
        uint64_t getMillisecondsSinceEpoch() const;
 | 
					        uint64_t getMillisecondsSinceEpoch() const;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,77 +5,72 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCobraMetricsThreadedPublisher.h"
 | 
					#include "IXCobraMetricsThreadedPublisher.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <cassert>
 | 
					 | 
				
			||||||
#include <cmath>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSetThreadName.h>
 | 
					#include <ixwebsocket/IXSetThreadName.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
					#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
				
			||||||
#include <sstream>
 | 
					#include <ixcore/utils/IXCoreLogger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
#include <stdexcept>
 | 
					#include <stdexcept>
 | 
				
			||||||
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CobraMetricsThreadedPublisher::CobraMetricsThreadedPublisher()
 | 
					    CobraMetricsThreadedPublisher::CobraMetricsThreadedPublisher() :
 | 
				
			||||||
        : _stop(false)
 | 
					        _stop(false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _cobra_connection.setEventCallback(
 | 
				
			||||||
 | 
					            []
 | 
				
			||||||
 | 
					            (ix::CobraConnectionEventType eventType,
 | 
				
			||||||
 | 
					             const std::string& errMsg,
 | 
				
			||||||
 | 
					             const ix::WebSocketHttpHeaders& headers,
 | 
				
			||||||
 | 
					             const std::string& subscriptionId,
 | 
				
			||||||
 | 
					             CobraConnection::MsgId msgId)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
        _cobra_connection.setEventCallback([](const CobraEventPtr& event) {
 | 
					 | 
				
			||||||
                std::stringstream ss;
 | 
					                std::stringstream ss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (event->type == ix::CobraEventType::Open)
 | 
					                if (eventType == ix::CobraConnection_EventType_Open)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ss << "Handshake headers" << std::endl;
 | 
					                    ss << "Handshake headers" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                for (auto&& it : event->headers)
 | 
					                    for (auto it : headers)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        ss << it.first << ": " << it.second << std::endl;
 | 
					                        ss << it.first << ": " << it.second << std::endl;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Authenticated)
 | 
					                else if (eventType == ix::CobraConnection_EventType_Authenticated)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ss << "Authenticated";
 | 
					                    ss << "Authenticated";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Error)
 | 
					                else if (eventType == ix::CobraConnection_EventType_Error)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                ss << "Error: " << event->errMsg;
 | 
					                    ss << "Error: " << errMsg;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Closed)
 | 
					                else if (eventType == ix::CobraConnection_EventType_Closed)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                ss << "Connection closed: " << event->errMsg;
 | 
					                    ss << "Connection closed: " << errMsg;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Subscribed)
 | 
					                else if (eventType == ix::CobraConnection_EventType_Subscribed)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                ss << "Subscribed through subscription id: " << event->subscriptionId;
 | 
					                    ss << "Subscribed through subscription id: " << subscriptionId;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::UnSubscribed)
 | 
					                else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                ss << "Unsubscribed through subscription id: " << event->subscriptionId;
 | 
					                    ss << "Unsubscribed through subscription id: " << subscriptionId;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Published)
 | 
					                else if (eventType == ix::CobraConnection_EventType_Published)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                ss << "Published message " << event->msgId << " acked";
 | 
					                    ss << "Published message " << msgId << " acked";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Pong)
 | 
					                else if (eventType == ix::CobraConnection_EventType_Pong)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ss << "Received websocket pong";
 | 
					                    ss << "Received websocket pong";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::HandshakeError)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ss << "Handshake error: " << event->errMsg;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::AuthenticationError)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ss << "Authentication error: " << event->errMsg;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::SubscriptionError)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ss << "Subscription error: " << event->errMsg;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            CoreLogger::log(ss.str().c_str());
 | 
					                ix::IXCoreLogger::Log(ss.str().c_str());
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,10 +95,11 @@ namespace ix
 | 
				
			|||||||
    void CobraMetricsThreadedPublisher::configure(const CobraConfig& config,
 | 
					    void CobraMetricsThreadedPublisher::configure(const CobraConfig& config,
 | 
				
			||||||
                                                  const std::string& channel)
 | 
					                                                  const std::string& channel)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        CoreLogger::log(config.socketTLSOptions.getDescription().c_str());
 | 
					        ix::IXCoreLogger::Log(config.socketTLSOptions.getDescription().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _channel = channel;
 | 
					        _channel = channel;
 | 
				
			||||||
        _cobra_connection.configure(config);
 | 
					        _cobra_connection.configure(config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CobraMetricsThreadedPublisher::pushMessage(MessageKind messageKind)
 | 
					    void CobraMetricsThreadedPublisher::pushMessage(MessageKind messageKind)
 | 
				
			||||||
@@ -161,15 +157,13 @@ namespace ix
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    _cobra_connection.suspend();
 | 
					                    _cobra_connection.suspend();
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                };
 | 
					                }; break;
 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case MessageKind::Resume:
 | 
					                case MessageKind::Resume:
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _cobra_connection.resume();
 | 
					                    _cobra_connection.resume();
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                };
 | 
					                }; break;
 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case MessageKind::Message:
 | 
					                case MessageKind::Message:
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -177,8 +171,7 @@ namespace ix
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _cobra_connection.publishNext();
 | 
					                        _cobra_connection.publishNext();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                };
 | 
					                }; break;
 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,8 @@ namespace ix
 | 
				
			|||||||
        ~CobraMetricsThreadedPublisher();
 | 
					        ~CobraMetricsThreadedPublisher();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Configuration / set keys, etc...
 | 
					        /// Configuration / set keys, etc...
 | 
				
			||||||
        void configure(const CobraConfig& config, const std::string& channel);
 | 
					        void configure(const CobraConfig& config,
 | 
				
			||||||
 | 
					                       const std::string& channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Start the worker thread, used for background publishing
 | 
					        /// Start the worker thread, used for background publishing
 | 
				
			||||||
        void start();
 | 
					        void start();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,44 +1,14 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCoreLogger.cpp
 | 
					 | 
				
			||||||
 *  Author: Thomas Wells, Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "ixcore/utils/IXCoreLogger.h"
 | 
					#include "ixcore/utils/IXCoreLogger.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Default do a no-op logger
 | 
					// Default do nothing logger
 | 
				
			||||||
    CoreLogger::LogFunc CoreLogger::_currentLogger = [](const char*, LogLevel) {};
 | 
					IXCoreLogger::LogFunc IXCoreLogger::_currentLogger = [](const char* /*msg*/){};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CoreLogger::log(const char* msg, LogLevel level)
 | 
					void IXCoreLogger::Log(const char* msg)
 | 
				
			||||||
    {
 | 
					{
 | 
				
			||||||
        _currentLogger(msg, level);
 | 
					    _currentLogger(msg);
 | 
				
			||||||
    }
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void CoreLogger::debug(const std::string& msg)
 | 
					} // ix
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _currentLogger(msg.c_str(), LogLevel::Debug);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void CoreLogger::info(const std::string& msg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _currentLogger(msg.c_str(), LogLevel::Info);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void CoreLogger::warn(const std::string& msg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _currentLogger(msg.c_str(), LogLevel::Warning);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void CoreLogger::error(const std::string& msg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _currentLogger(msg.c_str(), LogLevel::Error);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void CoreLogger::critical(const std::string& msg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _currentLogger(msg.c_str(), LogLevel::Critical);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,41 +1,15 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCoreLogger.h
 | 
					 | 
				
			||||||
 *  Author: Thomas Wells, Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    enum class LogLevel
 | 
					    class IXCoreLogger
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Debug = 0,
 | 
					 | 
				
			||||||
        Info = 1,
 | 
					 | 
				
			||||||
        Warning = 2,
 | 
					 | 
				
			||||||
        Error = 3,
 | 
					 | 
				
			||||||
        Critical = 4
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class CoreLogger
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        using LogFunc = std::function<void(const char*, LogLevel level)>;
 | 
					        using LogFunc = std::function<void(const char*)>;
 | 
				
			||||||
 | 
					        static void Log(const char* msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static void log(const char* msg, LogLevel level = LogLevel::Debug);
 | 
					        static void setLogFunction(LogFunc& func) { _currentLogger = func; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        static void debug(const std::string& msg);
 | 
					 | 
				
			||||||
        static void info(const std::string& msg);
 | 
					 | 
				
			||||||
        static void warn(const std::string& msg);
 | 
					 | 
				
			||||||
        static void error(const std::string& msg);
 | 
					 | 
				
			||||||
        static void critical(const std::string& msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static void setLogFunction(LogFunc& func)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _currentLogger = func;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        static LogFunc _currentLogger;
 | 
					        static LogFunc _currentLogger;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
					    static const std::string base64_chars =
 | 
				
			||||||
 | 
					    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
				
			||||||
    "abcdefghijklmnopqrstuvwxyz"
 | 
					    "abcdefghijklmnopqrstuvwxyz"
 | 
				
			||||||
    "0123456789+/";
 | 
					    "0123456789+/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,26 +50,26 @@ namespace ix
 | 
				
			|||||||
        unsigned char char_array_3[3];
 | 
					        unsigned char char_array_3[3];
 | 
				
			||||||
        unsigned char char_array_4[4];
 | 
					        unsigned char char_array_4[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (len--)
 | 
					        while(len--)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            char_array_3[i++] = *(bytes_to_encode++);
 | 
					            char_array_3[i++] = *(bytes_to_encode++);
 | 
				
			||||||
            if (i == 3)
 | 
					            if(i == 3)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
 | 
					                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
 | 
				
			||||||
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
 | 
					                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
 | 
				
			||||||
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
 | 
					                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
 | 
				
			||||||
                char_array_4[3] = char_array_3[2] & 0x3f;
 | 
					                char_array_4[3] = char_array_3[2] & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                for (i = 0; (i < 4); i++)
 | 
					                for(i = 0; (i <4) ; i++)
 | 
				
			||||||
                    ret += base64_chars[char_array_4[i]];
 | 
					                    ret += base64_chars[char_array_4[i]];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                i = 0;
 | 
					                i = 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (i)
 | 
					        if(i)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            for (j = i; j < 3; j++)
 | 
					            for(j = i; j < 3; j++)
 | 
				
			||||||
                char_array_3[j] = '\0';
 | 
					                char_array_3[j] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
 | 
					            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
 | 
				
			||||||
@@ -76,11 +77,12 @@ namespace ix
 | 
				
			|||||||
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
 | 
					            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
 | 
				
			||||||
            char_array_4[3] = char_array_3[2] & 0x3f;
 | 
					            char_array_4[3] = char_array_3[2] & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (j = 0; (j < i + 1); j++)
 | 
					            for(j = 0; (j < i + 1); j++)
 | 
				
			||||||
                ret += base64_chars[char_array_4[j]];
 | 
					                ret += base64_chars[char_array_4[j]];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while ((i++ < 3))
 | 
					            while((i++ < 3))
 | 
				
			||||||
                ret += '=';
 | 
					                ret += '=';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
@@ -93,7 +95,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::string base64_decode(const std::string& encoded_string)
 | 
					    std::string base64_decode(const std::string& encoded_string)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int in_len = (int) encoded_string.size();
 | 
					        int in_len = (int)encoded_string.size();
 | 
				
			||||||
        int i = 0;
 | 
					        int i = 0;
 | 
				
			||||||
        int j = 0;
 | 
					        int j = 0;
 | 
				
			||||||
        int in_ = 0;
 | 
					        int in_ = 0;
 | 
				
			||||||
@@ -101,42 +103,40 @@ namespace ix
 | 
				
			|||||||
        std::string ret;
 | 
					        std::string ret;
 | 
				
			||||||
        ret.reserve(((in_len + 3) / 4) * 3);
 | 
					        ret.reserve(((in_len + 3) / 4) * 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
 | 
					        while(in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            char_array_4[i++] = encoded_string[in_];
 | 
					            char_array_4[i++] = encoded_string[in_]; in_++;
 | 
				
			||||||
            in_++;
 | 
					            if(i ==4)
 | 
				
			||||||
            if (i == 4)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                for (i = 0; i < 4; i++)
 | 
					                for(i = 0; i <4; i++)
 | 
				
			||||||
                    char_array_4[i] = base64_chars.find(char_array_4[i]);
 | 
					                    char_array_4[i] = base64_chars.find(char_array_4[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
 | 
					                char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
 | 
				
			||||||
                char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
 | 
					                char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
 | 
				
			||||||
                char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 | 
					                char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                for (i = 0; (i < 3); i++)
 | 
					                for(i = 0; (i < 3); i++)
 | 
				
			||||||
                    ret += char_array_3[i];
 | 
					                    ret += char_array_3[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                i = 0;
 | 
					                i = 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (i)
 | 
					        if(i)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            for (j = i; j < 4; j++)
 | 
					            for(j = i; j <4; j++)
 | 
				
			||||||
                char_array_4[j] = 0;
 | 
					                char_array_4[j] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (j = 0; j < 4; j++)
 | 
					            for(j = 0; j <4; j++)
 | 
				
			||||||
                char_array_4[j] = base64_chars.find(char_array_4[j]);
 | 
					                char_array_4[j] = base64_chars.find(char_array_4[j]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
 | 
					            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
 | 
				
			||||||
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
 | 
					            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
 | 
				
			||||||
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 | 
					            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (j = 0; (j < i - 1); j++)
 | 
					            for(j = 0; (j < i - 1); j++) ret += char_array_3[j];
 | 
				
			||||||
                ret += char_array_3[j];
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,17 +5,16 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXHMac.h"
 | 
					#include "IXHMac.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXBase64.h"
 | 
					#include "IXBase64.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(IXCRYPTO_USE_MBED_TLS)
 | 
					#if defined(IXCRYPTO_USE_MBED_TLS)
 | 
				
			||||||
#include <mbedtls/md.h>
 | 
					# include <mbedtls/md.h>
 | 
				
			||||||
#elif defined(__APPLE__)
 | 
					#elif defined(__APPLE__)
 | 
				
			||||||
#include <CommonCrypto/CommonHMAC.h>
 | 
					# include <CommonCrypto/CommonHMAC.h>
 | 
				
			||||||
#elif defined(IXCRYPTO_USE_OPEN_SSL)
 | 
					#elif defined(IXCRYPTO_USE_OPEN_SSL)
 | 
				
			||||||
#include <openssl/hmac.h>
 | 
					# include <openssl/hmac.h>
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#include <assert.h>
 | 
					# include <assert.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -27,21 +26,19 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if defined(IXCRYPTO_USE_MBED_TLS)
 | 
					#if defined(IXCRYPTO_USE_MBED_TLS)
 | 
				
			||||||
        mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_MD5),
 | 
					        mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_MD5),
 | 
				
			||||||
                        (unsigned char*) key.c_str(),
 | 
					               (unsigned char *) key.c_str(), key.size(),
 | 
				
			||||||
                        key.size(),
 | 
					               (unsigned char *) data.c_str(), data.size(),
 | 
				
			||||||
                        (unsigned char*) data.c_str(),
 | 
					               (unsigned char *) &hash);
 | 
				
			||||||
                        data.size(),
 | 
					 | 
				
			||||||
                        (unsigned char*) &hash);
 | 
					 | 
				
			||||||
#elif defined(__APPLE__)
 | 
					#elif defined(__APPLE__)
 | 
				
			||||||
        CCHmac(kCCHmacAlgMD5, key.c_str(), key.size(), data.c_str(), data.size(), &hash);
 | 
					        CCHmac(kCCHmacAlgMD5,
 | 
				
			||||||
 | 
					               key.c_str(), key.size(),
 | 
				
			||||||
 | 
					               data.c_str(), data.size(),
 | 
				
			||||||
 | 
					               &hash);
 | 
				
			||||||
#elif defined(IXCRYPTO_USE_OPEN_SSL)
 | 
					#elif defined(IXCRYPTO_USE_OPEN_SSL)
 | 
				
			||||||
        HMAC(EVP_md5(),
 | 
					        HMAC(EVP_md5(),
 | 
				
			||||||
             key.c_str(),
 | 
					             key.c_str(), (int) key.size(),
 | 
				
			||||||
             (int) key.size(),
 | 
					             (unsigned char *) data.c_str(), (int) data.size(),
 | 
				
			||||||
             (unsigned char*) data.c_str(),
 | 
					             (unsigned char *) hash, nullptr);
 | 
				
			||||||
             (int) data.size(),
 | 
					 | 
				
			||||||
             (unsigned char*) hash,
 | 
					 | 
				
			||||||
             nullptr);
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        assert(false && "hmac not implemented on this platform");
 | 
					        assert(false && "hmac not implemented on this platform");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -50,4 +47,4 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return base64_encode(hashString, (uint32_t) hashString.size());
 | 
					        return base64_encode(hashString, (uint32_t) hashString.size());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,4 +19,4 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return hashAddress;
 | 
					        return hashAddress;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXUuid.h"
 | 
					#include "IXUuid.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iomanip>
 | 
					 | 
				
			||||||
#include <random>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <iomanip>
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -60,7 +60,7 @@ namespace ix
 | 
				
			|||||||
        ss << std::setw(8) << (a);
 | 
					        ss << std::setw(8) << (a);
 | 
				
			||||||
        ss << std::setw(4) << (b >> 16);
 | 
					        ss << std::setw(4) << (b >> 16);
 | 
				
			||||||
        ss << std::setw(4) << (b & 0xFFFF);
 | 
					        ss << std::setw(4) << (b & 0xFFFF);
 | 
				
			||||||
        ss << std::setw(4) << (c >> 16);
 | 
					        ss << std::setw(4) << (c >> 16 );
 | 
				
			||||||
        ss << std::setw(4) << (c & 0xFFFF);
 | 
					        ss << std::setw(4) << (c & 0xFFFF);
 | 
				
			||||||
        ss << std::setw(8) << d;
 | 
					        ss << std::setw(8) << d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,4 +72,4 @@ namespace ix
 | 
				
			|||||||
        Uuid id;
 | 
					        Uuid id;
 | 
				
			||||||
        return id.toString();
 | 
					        return id.toString();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,12 @@
 | 
				
			|||||||
#include "IXSentryClient.h"
 | 
					#include "IXSentryClient.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
					#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketVersion.h>
 | 
					#include <ixwebsocket/IXWebSocketVersion.h>
 | 
				
			||||||
#include <sstream>
 | 
					#include <ixcore/utils/IXCoreLogger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -64,8 +64,7 @@ namespace ix
 | 
				
			|||||||
    std::string SentryClient::computeAuthHeader()
 | 
					    std::string SentryClient::computeAuthHeader()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string securityHeader("Sentry sentry_version=5");
 | 
					        std::string securityHeader("Sentry sentry_version=5");
 | 
				
			||||||
        securityHeader += ",sentry_client=ws/";
 | 
					        securityHeader += ",sentry_client=ws/1.0.0";
 | 
				
			||||||
        securityHeader += std::string(IX_WEBSOCKET_VERSION);
 | 
					 | 
				
			||||||
        securityHeader += ",sentry_timestamp=" + std::to_string(SentryClient::getTimestamp());
 | 
					        securityHeader += ",sentry_timestamp=" + std::to_string(SentryClient::getTimestamp());
 | 
				
			||||||
        securityHeader += ",sentry_key=" + _publicKey;
 | 
					        securityHeader += ",sentry_key=" + _publicKey;
 | 
				
			||||||
        securityHeader += ",sentry_secret=" + _secretKey;
 | 
					        securityHeader += ",sentry_secret=" + _secretKey;
 | 
				
			||||||
@@ -226,39 +225,39 @@ namespace ix
 | 
				
			|||||||
        return _jsonWriter.write(payload);
 | 
					        return _jsonWriter.write(payload);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void SentryClient::send(
 | 
					    std::pair<HttpResponsePtr, std::string> SentryClient::send(const Json::Value& msg, bool verbose)
 | 
				
			||||||
        const Json::Value& msg,
 | 
					 | 
				
			||||||
        bool verbose,
 | 
					 | 
				
			||||||
        const OnResponseCallback& onResponseCallback)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto args = _httpClient->createRequest();
 | 
					        auto args = _httpClient->createRequest();
 | 
				
			||||||
        args->url = _url;
 | 
					 | 
				
			||||||
        args->verb = HttpClient::kPost;
 | 
					 | 
				
			||||||
        args->extraHeaders["X-Sentry-Auth"] = SentryClient::computeAuthHeader();
 | 
					        args->extraHeaders["X-Sentry-Auth"] = SentryClient::computeAuthHeader();
 | 
				
			||||||
        args->connectTimeout = 60;
 | 
					        args->connectTimeout = 60;
 | 
				
			||||||
        args->transferTimeout = 5 * 60;
 | 
					        args->transferTimeout = 5 * 60;
 | 
				
			||||||
        args->followRedirects = true;
 | 
					        args->followRedirects = true;
 | 
				
			||||||
        args->verbose = verbose;
 | 
					        args->verbose = verbose;
 | 
				
			||||||
        args->logger = [](const std::string& msg) { CoreLogger::log(msg.c_str()); };
 | 
					        args->logger = [](const std::string& msg) { ix::IXCoreLogger::Log(msg.c_str()); };
 | 
				
			||||||
        args->body = computePayload(msg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _httpClient->performRequest(args, onResponseCallback);
 | 
					        std::string body = computePayload(msg);
 | 
				
			||||||
 | 
					        HttpResponsePtr response = _httpClient->post(_url, body, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return std::make_pair(response, body);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // https://sentry.io/api/12345/minidump?sentry_key=abcdefgh");
 | 
					    // https://sentry.io/api/12345/minidump?sentry_key=abcdefgh");
 | 
				
			||||||
    std::string SentryClient::computeUrl(const std::string& project, const std::string& key)
 | 
					    std::string SentryClient::computeUrl(const std::string& project, const std::string& key)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << "https://sentry.io/api/" << project << "/minidump?sentry_key=" << key;
 | 
					        ss << "https://sentry.io/api/"
 | 
				
			||||||
 | 
					           << project
 | 
				
			||||||
 | 
					           << "/minidump?sentry_key="
 | 
				
			||||||
 | 
					           << key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ss.str();
 | 
					        return ss.str();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
    // curl -v -X POST -F upload_file_minidump=@ws/crash.dmp
 | 
					    // curl -v -X POST -F upload_file_minidump=@ws/crash.dmp 'https://sentry.io/api/123456/minidump?sentry_key=12344567890'
 | 
				
			||||||
    // 'https://sentry.io/api/123456/minidump?sentry_key=12344567890'
 | 
					 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
    void SentryClient::uploadMinidump(const std::string& sentryMetadata,
 | 
					    void SentryClient::uploadMinidump(
 | 
				
			||||||
 | 
					        const std::string& sentryMetadata,
 | 
				
			||||||
        const std::string& minidumpBytes,
 | 
					        const std::string& minidumpBytes,
 | 
				
			||||||
        const std::string& project,
 | 
					        const std::string& project,
 | 
				
			||||||
        const std::string& key,
 | 
					        const std::string& key,
 | 
				
			||||||
@@ -274,7 +273,7 @@ namespace ix
 | 
				
			|||||||
        args->followRedirects = true;
 | 
					        args->followRedirects = true;
 | 
				
			||||||
        args->verbose = verbose;
 | 
					        args->verbose = verbose;
 | 
				
			||||||
        args->multipartBoundary = multipartBoundary;
 | 
					        args->multipartBoundary = multipartBoundary;
 | 
				
			||||||
        args->logger = [](const std::string& msg) { CoreLogger::log(msg.c_str()); };
 | 
					        args->logger = [](const std::string& msg) { ix::IXCoreLogger::Log(msg.c_str()); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        HttpFormDataParameters httpFormDataParameters;
 | 
					        HttpFormDataParameters httpFormDataParameters;
 | 
				
			||||||
        httpFormDataParameters["upload_file_minidump"] = minidumpBytes;
 | 
					        httpFormDataParameters["upload_file_minidump"] = minidumpBytes;
 | 
				
			||||||
@@ -283,27 +282,7 @@ namespace ix
 | 
				
			|||||||
        httpParameters["sentry"] = sentryMetadata;
 | 
					        httpParameters["sentry"] = sentryMetadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        args->url = computeUrl(project, key);
 | 
					        args->url = computeUrl(project, key);
 | 
				
			||||||
        args->body = _httpClient->serializeHttpFormDataParameters(
 | 
					        args->body = _httpClient->serializeHttpFormDataParameters(multipartBoundary, httpFormDataParameters, httpParameters);
 | 
				
			||||||
            multipartBoundary, httpFormDataParameters, httpParameters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        _httpClient->performRequest(args, onResponseCallback);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void SentryClient::uploadPayload(const Json::Value& payload,
 | 
					 | 
				
			||||||
                                     bool verbose,
 | 
					 | 
				
			||||||
                                     const OnResponseCallback& onResponseCallback)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        auto args = _httpClient->createRequest();
 | 
					 | 
				
			||||||
        args->extraHeaders["X-Sentry-Auth"] = SentryClient::computeAuthHeader();
 | 
					 | 
				
			||||||
        args->verb = HttpClient::kPost;
 | 
					 | 
				
			||||||
        args->connectTimeout = 60;
 | 
					 | 
				
			||||||
        args->transferTimeout = 5 * 60;
 | 
					 | 
				
			||||||
        args->followRedirects = true;
 | 
					 | 
				
			||||||
        args->verbose = verbose;
 | 
					 | 
				
			||||||
        args->logger = [](const std::string& msg) { CoreLogger::log(msg.c_str()); };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        args->url = _url;
 | 
					 | 
				
			||||||
        args->body = _jsonWriter.write(payload);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _httpClient->performRequest(args, onResponseCallback);
 | 
					        _httpClient->performRequest(args, onResponseCallback);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,8 @@
 | 
				
			|||||||
#include <ixwebsocket/IXHttpClient.h>
 | 
					#include <ixwebsocket/IXHttpClient.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
					#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
				
			||||||
#include <json/json.h>
 | 
					#include <json/json.h>
 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <regex>
 | 
					#include <regex>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -21,26 +21,20 @@ namespace ix
 | 
				
			|||||||
        SentryClient(const std::string& dsn);
 | 
					        SentryClient(const std::string& dsn);
 | 
				
			||||||
        ~SentryClient() = default;
 | 
					        ~SentryClient() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void send(const Json::Value& msg,
 | 
					        std::pair<HttpResponsePtr, std::string> send(const Json::Value& msg, bool verbose);
 | 
				
			||||||
                  bool verbose,
 | 
					 | 
				
			||||||
                  const OnResponseCallback& onResponseCallback);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void uploadMinidump(const std::string& sentryMetadata,
 | 
					 | 
				
			||||||
                            const std::string& minidumpBytes,
 | 
					 | 
				
			||||||
                            const std::string& project,
 | 
					 | 
				
			||||||
                            const std::string& key,
 | 
					 | 
				
			||||||
                            bool verbose,
 | 
					 | 
				
			||||||
                            const OnResponseCallback& onResponseCallback);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void uploadPayload(const Json::Value& payload,
 | 
					 | 
				
			||||||
                           bool verbose,
 | 
					 | 
				
			||||||
                           const OnResponseCallback& onResponseCallback);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Json::Value parseLuaStackTrace(const std::string& stack);
 | 
					        Json::Value parseLuaStackTrace(const std::string& stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Mostly for testing
 | 
					        // Mostly for testing
 | 
				
			||||||
        void setTLSOptions(const SocketTLSOptions& tlsOptions);
 | 
					        void setTLSOptions(const SocketTLSOptions& tlsOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void uploadMinidump(
 | 
				
			||||||
 | 
					            const std::string& sentryMetadata,
 | 
				
			||||||
 | 
					            const std::string& minidumpBytes,
 | 
				
			||||||
 | 
					            const std::string& project,
 | 
				
			||||||
 | 
					            const std::string& key,
 | 
				
			||||||
 | 
					            bool verbose,
 | 
				
			||||||
 | 
					            const OnResponseCallback& onResponseCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        int64_t getTimestamp();
 | 
					        int64_t getTimestamp();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
					 | 
				
			||||||
#include <nlohmann/json.hpp>
 | 
					#include <nlohmann/json.hpp>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocketTLSOptions.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace snake
 | 
					namespace snake
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,10 @@ namespace ix
 | 
				
			|||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CancellationRequest cancellationRequest = []() -> bool { return false; };
 | 
					        CancellationRequest cancellationRequest = []() -> bool
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        return _socket->connect(hostname, port, errMsg, cancellationRequest);
 | 
					        return _socket->connect(hostname, port, errMsg, cancellationRequest);
 | 
				
			||||||
@@ -249,7 +252,8 @@ namespace ix
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string RedisClient::prepareXaddCommand(const std::string& stream,
 | 
					    std::string RedisClient::prepareXaddCommand(
 | 
				
			||||||
 | 
					        const std::string& stream,
 | 
				
			||||||
        const std::string& message)
 | 
					        const std::string& message)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
@@ -324,9 +328,7 @@ namespace ix
 | 
				
			|||||||
        return streamId;
 | 
					        return streamId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool RedisClient::sendCommand(const std::string& commands,
 | 
					    bool RedisClient::sendCommand(const std::string& commands, int commandsCount, std::string& errMsg)
 | 
				
			||||||
                                  int commandsCount,
 | 
					 | 
				
			||||||
                                  std::string& errMsg)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        bool sent = _socket->writeBytes(commands, nullptr);
 | 
					        bool sent = _socket->writeBytes(commands, nullptr);
 | 
				
			||||||
        if (!sent)
 | 
					        if (!sent)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <ixwebsocket/IXSocket.h>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class RedisClient
 | 
					    class RedisClient
 | 
				
			||||||
@@ -38,11 +39,14 @@ namespace ix
 | 
				
			|||||||
                       const OnRedisSubscribeCallback& callback);
 | 
					                       const OnRedisSubscribeCallback& callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // XADD
 | 
					        // XADD
 | 
				
			||||||
        std::string xadd(const std::string& channel,
 | 
					        std::string xadd(
 | 
				
			||||||
 | 
					            const std::string& channel,
 | 
				
			||||||
            const std::string& message,
 | 
					            const std::string& message,
 | 
				
			||||||
            std::string& errMsg);
 | 
					            std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string prepareXaddCommand(const std::string& stream, const std::string& message);
 | 
					        std::string prepareXaddCommand(
 | 
				
			||||||
 | 
					            const std::string& stream,
 | 
				
			||||||
 | 
					            const std::string& message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string readXaddReply(std::string& errMsg);
 | 
					        std::string readXaddReply(std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,18 +6,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXRedisServer.h"
 | 
					#include "IXRedisServer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXCancellationRequest.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXNetSystem.h>
 | 
					#include <ixwebsocket/IXNetSystem.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocket.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSocketConnect.h>
 | 
					#include <ixwebsocket/IXSocketConnect.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXCancellationRequest.h>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    RedisServer::RedisServer(
 | 
					    RedisServer::RedisServer(int port, const std::string& host, int backlog, size_t maxConnections, int addressFamily)
 | 
				
			||||||
        int port, const std::string& host, int backlog, size_t maxConnections, int addressFamily)
 | 
					 | 
				
			||||||
        : SocketServer(port, host, backlog, maxConnections, addressFamily)
 | 
					        : SocketServer(port, host, backlog, maxConnections, addressFamily)
 | 
				
			||||||
        , _connectedClientsCount(0)
 | 
					        , _connectedClientsCount(0)
 | 
				
			||||||
        , _stopHandlingConnections(false)
 | 
					        , _stopHandlingConnections(false)
 | 
				
			||||||
@@ -115,7 +114,8 @@ namespace ix
 | 
				
			|||||||
        for (auto it : _subscribers)
 | 
					        for (auto it : _subscribers)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::stringstream ss;
 | 
					            std::stringstream ss;
 | 
				
			||||||
            ss << "Subscription id: " << it.first << " #subscribers: " << it.second.size();
 | 
					            ss << "Subscription id: " << it.first
 | 
				
			||||||
 | 
					               << " #subscribers: " << it.second.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            logInfo(ss.str());
 | 
					            logInfo(ss.str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -126,7 +126,8 @@ namespace ix
 | 
				
			|||||||
        return _connectedClientsCount;
 | 
					        return _connectedClientsCount;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool RedisServer::startsWith(const std::string& str, const std::string& start)
 | 
					    bool RedisServer::startsWith(const std::string& str,
 | 
				
			||||||
 | 
					                                 const std::string& start)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return str.compare(0, start.length(), start) == 0;
 | 
					        return str.compare(0, start.length(), start) == 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -143,7 +144,8 @@ namespace ix
 | 
				
			|||||||
        return ss.str();
 | 
					        return ss.str();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool RedisServer::parseRequest(std::unique_ptr<Socket>& socket,
 | 
					    bool RedisServer::parseRequest(
 | 
				
			||||||
 | 
					        std::unique_ptr<Socket>& socket,
 | 
				
			||||||
        std::vector<std::string>& tokens)
 | 
					        std::vector<std::string>& tokens)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Parse first line
 | 
					        // Parse first line
 | 
				
			||||||
@@ -188,7 +190,8 @@ namespace ix
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool RedisServer::handleCommand(std::unique_ptr<Socket>& socket,
 | 
					    bool RedisServer::handleCommand(
 | 
				
			||||||
 | 
					        std::unique_ptr<Socket>& socket,
 | 
				
			||||||
        const std::vector<std::string>& tokens)
 | 
					        const std::vector<std::string>& tokens)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (tokens.size() != 1) return false;
 | 
					        if (tokens.size() != 1) return false;
 | 
				
			||||||
@@ -226,7 +229,8 @@ namespace ix
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool RedisServer::handleSubscribe(std::unique_ptr<Socket>& socket,
 | 
					    bool RedisServer::handleSubscribe(
 | 
				
			||||||
 | 
					        std::unique_ptr<Socket>& socket,
 | 
				
			||||||
        const std::vector<std::string>& tokens)
 | 
					        const std::vector<std::string>& tokens)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (tokens.size() != 2) return false;
 | 
					        if (tokens.size() != 2) return false;
 | 
				
			||||||
@@ -246,7 +250,8 @@ namespace ix
 | 
				
			|||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool RedisServer::handlePublish(std::unique_ptr<Socket>& socket,
 | 
					    bool RedisServer::handlePublish(
 | 
				
			||||||
 | 
					        std::unique_ptr<Socket>& socket,
 | 
				
			||||||
        const std::vector<std::string>& tokens)
 | 
					        const std::vector<std::string>& tokens)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (tokens.size() != 3) return false;
 | 
					        if (tokens.size() != 3) return false;
 | 
				
			||||||
@@ -276,7 +281,9 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // return the number of clients that received the message.
 | 
					        // return the number of clients that received the message.
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << ":" << std::to_string(subscribers.size()) << "\r\n";
 | 
					        ss << ":"
 | 
				
			||||||
 | 
					           << std::to_string(subscribers.size())
 | 
				
			||||||
 | 
					           << "\r\n";
 | 
				
			||||||
        socket->writeBytes(ss.str(), cb);
 | 
					        socket->writeBytes(ss.str(), cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,13 +6,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXSocket.h"
 | 
					 | 
				
			||||||
#include "IXSocketServer.h"
 | 
					#include "IXSocketServer.h"
 | 
				
			||||||
 | 
					#include "IXSocket.h"
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <map>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
#include <utility> // pair
 | 
					#include <utility> // pair
 | 
				
			||||||
@@ -50,14 +50,18 @@ namespace ix
 | 
				
			|||||||
        bool startsWith(const std::string& str, const std::string& start);
 | 
					        bool startsWith(const std::string& str, const std::string& start);
 | 
				
			||||||
        std::string writeString(const std::string& str);
 | 
					        std::string writeString(const std::string& str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool parseRequest(std::unique_ptr<Socket>& socket, std::vector<std::string>& tokens);
 | 
					        bool parseRequest(
 | 
				
			||||||
 | 
					            std::unique_ptr<Socket>& socket,
 | 
				
			||||||
 | 
					            std::vector<std::string>& tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool handlePublish(std::unique_ptr<Socket>& socket, const std::vector<std::string>& tokens);
 | 
					        bool handlePublish(std::unique_ptr<Socket>& socket,
 | 
				
			||||||
 | 
					                           const std::vector<std::string>& tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool handleSubscribe(std::unique_ptr<Socket>& socket,
 | 
					        bool handleSubscribe(std::unique_ptr<Socket>& socket,
 | 
				
			||||||
                             const std::vector<std::string>& tokens);
 | 
					                             const std::vector<std::string>& tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool handleCommand(std::unique_ptr<Socket>& socket, const std::vector<std::string>& tokens);
 | 
					        bool handleCommand(std::unique_ptr<Socket>& socket,
 | 
				
			||||||
 | 
					                           const std::vector<std::string>& tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void cleanupSubscribers(std::unique_ptr<Socket>& socket);
 | 
					        void cleanupSubscribers(std::unique_ptr<Socket>& socket);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,9 +10,9 @@
 | 
				
			|||||||
#include "IXSnakeConnectionState.h"
 | 
					#include "IXSnakeConnectionState.h"
 | 
				
			||||||
#include "nlohmann/json.hpp"
 | 
					#include "nlohmann/json.hpp"
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					 | 
				
			||||||
#include <ixcrypto/IXHMac.h>
 | 
					#include <ixcrypto/IXHMac.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
 | 
					#include <ixcore/utils/IXCoreLogger.h>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace snake
 | 
					namespace snake
 | 
				
			||||||
@@ -189,8 +189,7 @@ namespace snake
 | 
				
			|||||||
            nlohmann::json response = {
 | 
					            nlohmann::json response = {
 | 
				
			||||||
                {"action", "rtm/subscription/data"},
 | 
					                {"action", "rtm/subscription/data"},
 | 
				
			||||||
                {"id", id++},
 | 
					                {"id", id++},
 | 
				
			||||||
                {"body",
 | 
					                {"body", {{"subscription_id", subscriptionId}, {"position", "0-0"}, {"messages", {msg}}}}};
 | 
				
			||||||
                 {{"subscription_id", subscriptionId}, {"position", "0-0"}, {"messages", {msg}}}}};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ws->sendText(response.dump());
 | 
					            ws->sendText(response.dump());
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -198,7 +197,7 @@ namespace snake
 | 
				
			|||||||
        auto responseCallback = [ws, pdu, &subscriptionId](const std::string& redisResponse) {
 | 
					        auto responseCallback = [ws, pdu, &subscriptionId](const std::string& redisResponse) {
 | 
				
			||||||
            std::stringstream ss;
 | 
					            std::stringstream ss;
 | 
				
			||||||
            ss << "Redis Response: " << redisResponse << "...";
 | 
					            ss << "Redis Response: " << redisResponse << "...";
 | 
				
			||||||
            ix::CoreLogger::log(ss.str().c_str());
 | 
					            ix::IXCoreLogger::Log(ss.str().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Success
 | 
					            // Success
 | 
				
			||||||
            nlohmann::json response = {{"action", "rtm/subscribe/ok"},
 | 
					            nlohmann::json response = {{"action", "rtm/subscribe/ok"},
 | 
				
			||||||
@@ -210,7 +209,7 @@ namespace snake
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            std::stringstream ss;
 | 
					            std::stringstream ss;
 | 
				
			||||||
            ss << "Subscribing to " << appChannel << "...";
 | 
					            ss << "Subscribing to " << appChannel << "...";
 | 
				
			||||||
            ix::CoreLogger::log(ss.str().c_str());
 | 
					            ix::IXCoreLogger::Log(ss.str().c_str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!redisClient.subscribe(appChannel, responseCallback, callback))
 | 
					        if (!redisClient.subscribe(appChannel, responseCallback, callback))
 | 
				
			||||||
@@ -252,21 +251,7 @@ namespace snake
 | 
				
			|||||||
                             const AppConfig& appConfig,
 | 
					                             const AppConfig& appConfig,
 | 
				
			||||||
                             const std::string& str)
 | 
					                             const std::string& str)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        nlohmann::json pdu;
 | 
					        auto pdu = nlohmann::json::parse(str);
 | 
				
			||||||
        try
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            pdu = nlohmann::json::parse(str);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch (const nlohmann::json::parse_error& e)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::stringstream ss;
 | 
					 | 
				
			||||||
            ss << "malformed json pdu: " << e.what() << " -> " << str << "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            nlohmann::json response = {{"body", {{"error", "invalid_json"}, {"reason", ss.str()}}}};
 | 
					 | 
				
			||||||
            ws->sendText(response.dump());
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto action = pdu["action"];
 | 
					        auto action = pdu["action"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (action == "auth/handshake")
 | 
					        if (action == "auth/handshake")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,8 @@
 | 
				
			|||||||
#include "IXSnakeConnectionState.h"
 | 
					#include "IXSnakeConnectionState.h"
 | 
				
			||||||
#include "IXSnakeProtocol.h"
 | 
					#include "IXSnakeProtocol.h"
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <ixcore/utils/IXCoreLogger.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace snake
 | 
					namespace snake
 | 
				
			||||||
@@ -29,7 +29,7 @@ namespace snake
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << "Listening on " << appConfig.hostname << ":" << appConfig.port;
 | 
					        ss << "Listening on " << appConfig.hostname << ":" << appConfig.port;
 | 
				
			||||||
        ix::CoreLogger::log(ss.str().c_str());
 | 
					        ix::IXCoreLogger::Log(ss.str().c_str());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
@@ -67,7 +67,6 @@ namespace snake
 | 
				
			|||||||
                webSocket->setOnMessageCallback(
 | 
					                webSocket->setOnMessageCallback(
 | 
				
			||||||
                    [this, webSocket, state](const ix::WebSocketMessagePtr& msg) {
 | 
					                    [this, webSocket, state](const ix::WebSocketMessagePtr& msg) {
 | 
				
			||||||
                        std::stringstream ss;
 | 
					                        std::stringstream ss;
 | 
				
			||||||
                        ix::LogLevel logLevel = ix::LogLevel::Debug;
 | 
					 | 
				
			||||||
                        if (msg->type == ix::WebSocketMessageType::Open)
 | 
					                        if (msg->type == ix::WebSocketMessageType::Open)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            ss << "New connection" << std::endl;
 | 
					                            ss << "New connection" << std::endl;
 | 
				
			||||||
@@ -87,7 +86,6 @@ namespace snake
 | 
				
			|||||||
                                                              _appConfig.redisPort))
 | 
					                                                              _appConfig.redisPort))
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                ss << "Cannot connect to redis host" << std::endl;
 | 
					                                ss << "Cannot connect to redis host" << std::endl;
 | 
				
			||||||
                                logLevel = ix::LogLevel::Error;
 | 
					 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else if (msg->type == ix::WebSocketMessageType::Close)
 | 
					                        else if (msg->type == ix::WebSocketMessageType::Close)
 | 
				
			||||||
@@ -103,7 +101,6 @@ namespace snake
 | 
				
			|||||||
                            ss << "#retries: " << msg->errorInfo.retries << std::endl;
 | 
					                            ss << "#retries: " << msg->errorInfo.retries << std::endl;
 | 
				
			||||||
                            ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
 | 
					                            ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
 | 
				
			||||||
                            ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
 | 
					                            ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
 | 
				
			||||||
                            logLevel = ix::LogLevel::Error;
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else if (msg->type == ix::WebSocketMessageType::Fragment)
 | 
					                        else if (msg->type == ix::WebSocketMessageType::Fragment)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -115,7 +112,7 @@ namespace snake
 | 
				
			|||||||
                            processCobraMessage(state, webSocket, _appConfig, msg->str);
 | 
					                            processCobraMessage(state, webSocket, _appConfig, msg->str);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        ix::CoreLogger::log(ss.str().c_str(), logLevel);
 | 
					                        ix::IXCoreLogger::Log(ss.str().c_str());
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXCancellationRequest.h"
 | 
					#include "IXCancellationRequest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cassert>
 | 
					 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -14,8 +13,6 @@ namespace ix
 | 
				
			|||||||
    CancellationRequest makeCancellationRequestWithTimeout(
 | 
					    CancellationRequest makeCancellationRequestWithTimeout(
 | 
				
			||||||
        int secs, std::atomic<bool>& requestInitCancellation)
 | 
					        int secs, std::atomic<bool>& requestInitCancellation)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        assert(secs > 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto start = std::chrono::system_clock::now();
 | 
					        auto start = std::chrono::system_clock::now();
 | 
				
			||||||
        auto timeout = std::chrono::seconds(secs);
 | 
					        auto timeout = std::chrono::seconds(secs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,19 +4,6 @@
 | 
				
			|||||||
 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// On Windows Universal Platform (uwp), gai_strerror defaults behavior is to returns wchar_t
 | 
					 | 
				
			||||||
// which is different from all other platforms. We want the non unicode version.
 | 
					 | 
				
			||||||
// See https://github.com/microsoft/vcpkg/pull/11030
 | 
					 | 
				
			||||||
// We could do this in IXNetSystem.cpp but so far we are only using gai_strerror in here.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
#ifdef _UNICODE
 | 
					 | 
				
			||||||
#undef _UNICODE
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef UNICODE
 | 
					 | 
				
			||||||
#undef UNICODE
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXDNSLookup.h"
 | 
					#include "IXDNSLookup.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXNetSystem.h"
 | 
					#include "IXNetSystem.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,12 +78,12 @@ namespace ix
 | 
				
			|||||||
        WebSocketHttpHeaders extraHeaders;
 | 
					        WebSocketHttpHeaders extraHeaders;
 | 
				
			||||||
        std::string body;
 | 
					        std::string body;
 | 
				
			||||||
        std::string multipartBoundary;
 | 
					        std::string multipartBoundary;
 | 
				
			||||||
        int connectTimeout = 60;
 | 
					        int connectTimeout;
 | 
				
			||||||
        int transferTimeout = 1800;
 | 
					        int transferTimeout;
 | 
				
			||||||
        bool followRedirects = true;
 | 
					        bool followRedirects;
 | 
				
			||||||
        int maxRedirects = 5;
 | 
					        int maxRedirects;
 | 
				
			||||||
        bool verbose = false;
 | 
					        bool verbose;
 | 
				
			||||||
        bool compress = true;
 | 
					        bool compress;
 | 
				
			||||||
        Logger logger;
 | 
					        Logger logger;
 | 
				
			||||||
        OnProgressCallback onProgressCallback;
 | 
					        OnProgressCallback onProgressCallback;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,12 +25,10 @@ namespace ix
 | 
				
			|||||||
    const std::string HttpClient::kHead = "HEAD";
 | 
					    const std::string HttpClient::kHead = "HEAD";
 | 
				
			||||||
    const std::string HttpClient::kDel = "DEL";
 | 
					    const std::string HttpClient::kDel = "DEL";
 | 
				
			||||||
    const std::string HttpClient::kPut = "PUT";
 | 
					    const std::string HttpClient::kPut = "PUT";
 | 
				
			||||||
    const std::string HttpClient::kPatch = "PATCH";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HttpClient::HttpClient(bool async)
 | 
					    HttpClient::HttpClient(bool async)
 | 
				
			||||||
        : _async(async)
 | 
					        : _async(async)
 | 
				
			||||||
        , _stop(false)
 | 
					        , _stop(false)
 | 
				
			||||||
        , _forceBody(false)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (!_async) return;
 | 
					        if (!_async) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,11 +49,6 @@ namespace ix
 | 
				
			|||||||
        _tlsOptions = tlsOptions;
 | 
					        _tlsOptions = tlsOptions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void HttpClient::setForceBody(bool value)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        _forceBody = value;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    HttpRequestArgsPtr HttpClient::createRequest(const std::string& url, const std::string& verb)
 | 
					    HttpRequestArgsPtr HttpClient::createRequest(const std::string& url, const std::string& verb)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto request = std::make_shared<HttpRequestArgs>();
 | 
					        auto request = std::make_shared<HttpRequestArgs>();
 | 
				
			||||||
@@ -199,7 +192,7 @@ namespace ix
 | 
				
			|||||||
            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
					            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (verb == kPost || verb == kPut || verb == kPatch || _forceBody)
 | 
					        if (verb == kPost || verb == kPut)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ss << "Content-Length: " << body.size() << "\r\n";
 | 
					            ss << "Content-Length: " << body.size() << "\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -227,10 +220,11 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::string req(ss.str());
 | 
					        std::string req(ss.str());
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
 | 
					        std::atomic<bool> requestInitCancellation(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Make a cancellation object dealing with connection timeout
 | 
					        // Make a cancellation object dealing with connection timeout
 | 
				
			||||||
        auto isCancellationRequested =
 | 
					        auto isCancellationRequested =
 | 
				
			||||||
            makeCancellationRequestWithTimeout(args->connectTimeout, _stop);
 | 
					            makeCancellationRequestWithTimeout(args->connectTimeout, requestInitCancellation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool success = _socket->connect(host, port, errMsg, isCancellationRequested);
 | 
					        bool success = _socket->connect(host, port, errMsg, isCancellationRequested);
 | 
				
			||||||
        if (!success)
 | 
					        if (!success)
 | 
				
			||||||
@@ -248,7 +242,8 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Make a new cancellation object dealing with transfer timeout
 | 
					        // Make a new cancellation object dealing with transfer timeout
 | 
				
			||||||
        isCancellationRequested = makeCancellationRequestWithTimeout(args->transferTimeout, _stop);
 | 
					        isCancellationRequested =
 | 
				
			||||||
 | 
					            makeCancellationRequestWithTimeout(args->transferTimeout, requestInitCancellation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (args->verbose)
 | 
					        if (args->verbose)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -567,20 +562,6 @@ namespace ix
 | 
				
			|||||||
        return request(url, kPut, body, args);
 | 
					        return request(url, kPut, body, args);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HttpResponsePtr HttpClient::patch(const std::string& url,
 | 
					 | 
				
			||||||
                                      const HttpParameters& httpParameters,
 | 
					 | 
				
			||||||
                                      HttpRequestArgsPtr args)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return request(url, kPatch, serializeHttpParameters(httpParameters), args);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    HttpResponsePtr HttpClient::patch(const std::string& url,
 | 
					 | 
				
			||||||
                                      const std::string& body,
 | 
					 | 
				
			||||||
                                      const HttpRequestArgsPtr args)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return request(url, kPatch, body, args);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string HttpClient::urlEncode(const std::string& value)
 | 
					    std::string HttpClient::urlEncode(const std::string& value)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::ostringstream escaped;
 | 
					        std::ostringstream escaped;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,19 +46,12 @@ namespace ix
 | 
				
			|||||||
                            const std::string& body,
 | 
					                            const std::string& body,
 | 
				
			||||||
                            HttpRequestArgsPtr args);
 | 
					                            HttpRequestArgsPtr args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        HttpResponsePtr patch(const std::string& url,
 | 
					 | 
				
			||||||
                              const HttpParameters& httpParameters,
 | 
					 | 
				
			||||||
                              HttpRequestArgsPtr args);
 | 
					 | 
				
			||||||
        HttpResponsePtr patch(const std::string& url,
 | 
					 | 
				
			||||||
                              const std::string& body,
 | 
					 | 
				
			||||||
                              HttpRequestArgsPtr args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        HttpResponsePtr request(const std::string& url,
 | 
					        HttpResponsePtr request(const std::string& url,
 | 
				
			||||||
                                const std::string& verb,
 | 
					                                const std::string& verb,
 | 
				
			||||||
                                const std::string& body,
 | 
					                                const std::string& body,
 | 
				
			||||||
                                HttpRequestArgsPtr args,
 | 
					                                HttpRequestArgsPtr args,
 | 
				
			||||||
                                int redirects = 0);
 | 
					                                int redirects = 0);
 | 
				
			||||||
        void setForceBody(bool value);
 | 
					
 | 
				
			||||||
        // Async API
 | 
					        // Async API
 | 
				
			||||||
        HttpRequestArgsPtr createRequest(const std::string& url = std::string(),
 | 
					        HttpRequestArgsPtr createRequest(const std::string& url = std::string(),
 | 
				
			||||||
                                         const std::string& verb = HttpClient::kGet);
 | 
					                                         const std::string& verb = HttpClient::kGet);
 | 
				
			||||||
@@ -85,7 +78,6 @@ namespace ix
 | 
				
			|||||||
        const static std::string kHead;
 | 
					        const static std::string kHead;
 | 
				
			||||||
        const static std::string kDel;
 | 
					        const static std::string kDel;
 | 
				
			||||||
        const static std::string kPut;
 | 
					        const static std::string kPut;
 | 
				
			||||||
        const static std::string kPatch;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        void log(const std::string& msg, HttpRequestArgsPtr args);
 | 
					        void log(const std::string& msg, HttpRequestArgsPtr args);
 | 
				
			||||||
@@ -94,6 +86,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Async API background thread runner
 | 
					        // Async API background thread runner
 | 
				
			||||||
        void run();
 | 
					        void run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Async API
 | 
					        // Async API
 | 
				
			||||||
        bool _async;
 | 
					        bool _async;
 | 
				
			||||||
        std::queue<std::pair<HttpRequestArgsPtr, OnResponseCallback>> _queue;
 | 
					        std::queue<std::pair<HttpRequestArgsPtr, OnResponseCallback>> _queue;
 | 
				
			||||||
@@ -106,7 +99,5 @@ namespace ix
 | 
				
			|||||||
        std::mutex _mutex; // to protect accessing the _socket (only one socket per client)
 | 
					        std::mutex _mutex; // to protect accessing the _socket (only one socket per client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SocketTLSOptions _tlsOptions;
 | 
					        SocketTLSOptions _tlsOptions;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool _forceBody;
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,6 @@ typedef unsigned long int nfds_t;
 | 
				
			|||||||
#else
 | 
					#else
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <netdb.h>
 | 
					#include <netdb.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
#include <netinet/ip.h>
 | 
					#include <netinet/ip.h>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										115
									
								
								ixwebsocket/IXSelectInterruptEventFd.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								ixwebsocket/IXSelectInterruptEventFd.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXSelectInterruptEventFd.cpp
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// On Linux we use eventd to wake up select.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Linux/Android has a special type of virtual files. select(2) will react
 | 
				
			||||||
 | 
					// when reading/writing to those files, unlike closing sockets.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// https://linux.die.net/man/2/eventfd
 | 
				
			||||||
 | 
					// http://www.sourcexr.com/articles/2013/10/26/lightweight-inter-process-signaling-with-eventfd
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// eventfd was added in Linux kernel 2.x, and our oldest Android (Kitkat 4.4)
 | 
				
			||||||
 | 
					// is on Kernel 3.x
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// cf Android/Kernel table here
 | 
				
			||||||
 | 
					// https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// On macOS we use UNIX pipes to wake up select.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXSelectInterruptEventFd.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <string.h> // for strerror
 | 
				
			||||||
 | 
					#include <sys/eventfd.h>
 | 
				
			||||||
 | 
					#include <unistd.h> // for write
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    SelectInterruptEventFd::SelectInterruptEventFd()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _eventfd = -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SelectInterruptEventFd::~SelectInterruptEventFd()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ::close(_eventfd);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool SelectInterruptEventFd::init(std::string& errorMsg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // calling init twice is a programming error
 | 
				
			||||||
 | 
					        assert(_eventfd == -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _eventfd = eventfd(0, 0);
 | 
				
			||||||
 | 
					        if (_eventfd < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::stringstream ss;
 | 
				
			||||||
 | 
					            ss << "SelectInterruptEventFd::init() failed in eventfd()"
 | 
				
			||||||
 | 
					               << " : " << strerror(errno);
 | 
				
			||||||
 | 
					            errorMsg = ss.str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _eventfd = -1;
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fcntl(_eventfd, F_SETFL, O_NONBLOCK) == -1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::stringstream ss;
 | 
				
			||||||
 | 
					            ss << "SelectInterruptEventFd::init() failed in fcntl() call"
 | 
				
			||||||
 | 
					               << " : " << strerror(errno);
 | 
				
			||||||
 | 
					            errorMsg = ss.str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _eventfd = -1;
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool SelectInterruptEventFd::notify(uint64_t value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int fd = _eventfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fd == -1) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // we should write 8 bytes for an uint64_t
 | 
				
			||||||
 | 
					        return write(fd, &value, sizeof(value)) == 8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: return max uint64_t for errors ?
 | 
				
			||||||
 | 
					    uint64_t SelectInterruptEventFd::read()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int fd = _eventfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint64_t value = 0;
 | 
				
			||||||
 | 
					        ::read(fd, &value, sizeof(value));
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool SelectInterruptEventFd::clear()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (_eventfd == -1) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 0 is a special value ; select will not wake up
 | 
				
			||||||
 | 
					        uint64_t value = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // we should write 8 bytes for an uint64_t
 | 
				
			||||||
 | 
					        return write(_eventfd, &value, sizeof(value)) == 8;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int SelectInterruptEventFd::getFd() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return _eventfd;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} // namespace ix
 | 
				
			||||||
							
								
								
									
										31
									
								
								ixwebsocket/IXSelectInterruptEventFd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								ixwebsocket/IXSelectInterruptEventFd.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXSelectInterruptEventFd.h
 | 
				
			||||||
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 | 
					 *  Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXSelectInterrupt.h"
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class SelectInterruptEventFd final : public SelectInterrupt
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        SelectInterruptEventFd();
 | 
				
			||||||
 | 
					        virtual ~SelectInterruptEventFd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool init(std::string& errorMsg) final;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool notify(uint64_t value) final;
 | 
				
			||||||
 | 
					        bool clear() final;
 | 
				
			||||||
 | 
					        uint64_t read() final;
 | 
				
			||||||
 | 
					        int getFd() const final;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        int _eventfd;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					} // namespace ix
 | 
				
			||||||
@@ -376,8 +376,7 @@ namespace ix
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (isCancellationRequested && isCancellationRequested())
 | 
					            if (isCancellationRequested && isCancellationRequested())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                const std::string errorMsg("Cancellation Requested");
 | 
					                return std::make_pair(false, std::string());
 | 
				
			||||||
                return std::make_pair(false, errorMsg);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            size_t size = std::min(kChunkSize, length - output.size());
 | 
					            size_t size = std::min(kChunkSize, length - output.size());
 | 
				
			||||||
@@ -389,8 +388,7 @@ namespace ix
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (ret <= 0 && !Socket::isWaitNeeded())
 | 
					            else if (ret <= 0 && !Socket::isWaitNeeded())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                const std::string errorMsg("Recv Error");
 | 
					                return std::make_pair(false, std::string());
 | 
				
			||||||
                return std::make_pair(false, errorMsg);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (onProgressCallback) onProgressCallback((int) output.size(), (int) length);
 | 
					            if (onProgressCallback) onProgressCallback((int) output.size(), (int) length);
 | 
				
			||||||
@@ -399,8 +397,7 @@ namespace ix
 | 
				
			|||||||
            // This way we are not busy looping
 | 
					            // This way we are not busy looping
 | 
				
			||||||
            if (isReadyToRead(1) == PollResultType::Error)
 | 
					            if (isReadyToRead(1) == PollResultType::Error)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                const std::string errorMsg("Poll Error");
 | 
					                return std::make_pair(false, std::string());
 | 
				
			||||||
                return std::make_pair(false, errorMsg);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,10 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  IXSocketAppleSSL.cpp
 | 
					 *  IXSocketAppleSSL.cpp
 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 *  Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Adapted from Satori SDK Apple SSL code.
 | 
					 *  Adapted from Satori SDK Apple SSL code.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_SECURE_TRANSPORT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXSocketAppleSSL.h"
 | 
					#include "IXSocketAppleSSL.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXSocketConnect.h"
 | 
					#include "IXSocketConnect.h"
 | 
				
			||||||
@@ -309,5 +307,3 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // IXWEBSOCKET_USE_SECURE_TRANSPORT
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  IXSocketAppleSSL.h
 | 
					 *  IXSocketAppleSSL.h
 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 *  Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_SECURE_TRANSPORT
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,5 +47,3 @@ namespace ix
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // IXWEBSOCKET_USE_SECURE_TRANSPORT
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,12 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  IXSocketMbedTLS.cpp
 | 
					 *  IXSocketMbedTLS.cpp
 | 
				
			||||||
 *  Author: Benjamin Sergeant, Max Weisel
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Some code taken from
 | 
					 *  Some code taken from
 | 
				
			||||||
 *  https://github.com/rottor12/WsClientLib/blob/master/lib/src/WsClientLib.cpp
 | 
					 *  https://github.com/rottor12/WsClientLib/blob/master/lib/src/WsClientLib.cpp
 | 
				
			||||||
 *  and mini_client.c example from mbedtls
 | 
					 *  and mini_client.c example from mbedtls
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_MBED_TLS
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXSocketMbedTLS.h"
 | 
					#include "IXSocketMbedTLS.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,55 +42,6 @@ namespace ix
 | 
				
			|||||||
        mbedtls_pk_init(&_pkey);
 | 
					        mbedtls_pk_init(&_pkey);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
        DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG |
 | 
					 | 
				
			||||||
                      CERT_SYSTEM_STORE_CURRENT_USER;
 | 
					 | 
				
			||||||
        HCERTSTORE systemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, flags, L"Root");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!systemStore)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            errorMsg = "CertOpenStore failed with ";
 | 
					 | 
				
			||||||
            errorMsg += std::to_string(GetLastError());
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PCCERT_CONTEXT certificateIterator = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int certificateCount = 0;
 | 
					 | 
				
			||||||
        while (certificateIterator = CertEnumCertificatesInStore(systemStore, certificateIterator))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (certificateIterator->dwCertEncodingType & X509_ASN_ENCODING)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                int ret = mbedtls_x509_crt_parse(&_cacert,
 | 
					 | 
				
			||||||
                                                 certificateIterator->pbCertEncoded,
 | 
					 | 
				
			||||||
                                                 certificateIterator->cbCertEncoded);
 | 
					 | 
				
			||||||
                if (ret == 0)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    ++certificateCount;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CertFreeCertificateContext(certificateIterator);
 | 
					 | 
				
			||||||
        CertCloseStore(systemStore, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (certificateCount == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            errorMsg = "No certificates found";
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        // On macOS we can query the system cert location from the keychain
 | 
					 | 
				
			||||||
        // On Linux we could try to fetch some local files based on the distribution
 | 
					 | 
				
			||||||
        // On Android we could use JNI to get to the system certs
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg)
 | 
					    bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        initMBedTLS();
 | 
					        initMBedTLS();
 | 
				
			||||||
@@ -145,37 +95,19 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // FIXME: should we call mbedtls_ssl_conf_verify ?
 | 
					 | 
				
			||||||
            mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
 | 
					            mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // FIXME: should we call mbedtls_ssl_conf_verify ?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (_tlsOptions.isUsingSystemDefaults())
 | 
					            if (_tlsOptions.isUsingSystemDefaults())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!loadSystemCertificates(errMsg))
 | 
					                ; // FIXME
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    return false;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (_tlsOptions.isUsingInMemoryCAs())
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    const char* buffer = _tlsOptions.caFile.c_str();
 | 
					 | 
				
			||||||
                    size_t bufferSize =
 | 
					 | 
				
			||||||
                        _tlsOptions.caFile.size() + 1; // Needs to include null terminating
 | 
					 | 
				
			||||||
                                                       // character otherwise mbedtls will fail.
 | 
					 | 
				
			||||||
                    if (mbedtls_x509_crt_parse(
 | 
					 | 
				
			||||||
                            &_cacert, (const unsigned char*) buffer, bufferSize) < 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        errMsg = "Cannot parse CA from memory.";
 | 
					 | 
				
			||||||
                        return false;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (mbedtls_x509_crt_parse_file(&_cacert, _tlsOptions.caFile.c_str()) < 0)
 | 
					            else if (mbedtls_x509_crt_parse_file(&_cacert, _tlsOptions.caFile.c_str()) < 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                errMsg = "Cannot parse CA file '" + _tlsOptions.caFile + "'";
 | 
					                errMsg = "Cannot parse CA file '" + _tlsOptions.caFile + "'";
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mbedtls_ssl_conf_ca_chain(&_conf, &_cacert, NULL);
 | 
					            mbedtls_ssl_conf_ca_chain(&_conf, &_cacert, NULL);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -348,5 +280,3 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // IXWEBSOCKET_USE_MBED_TLS
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  IXSocketMbedTLS.h
 | 
					 *  IXSocketMbedTLS.h
 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 *  Copyright (c) 2019-2020 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_MBED_TLS
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,9 +51,6 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        bool init(const std::string& host, bool isClient, std::string& errMsg);
 | 
					        bool init(const std::string& host, bool isClient, std::string& errMsg);
 | 
				
			||||||
        void initMBedTLS();
 | 
					        void initMBedTLS();
 | 
				
			||||||
        bool loadSystemCertificates(std::string& errMsg);
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // IXWEBSOCKET_USE_MBED_TLS
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,10 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  IXSocketOpenSSL.cpp
 | 
					 *  IXSocketOpenSSL.cpp
 | 
				
			||||||
 *  Author: Benjamin Sergeant, Matt DeBoer, Max Weisel
 | 
					 *  Author: Benjamin Sergeant, Matt DeBoer
 | 
				
			||||||
 *  Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Adapted from Satori SDK OpenSSL code.
 | 
					 *  Adapted from Satori SDK OpenSSL code.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_OPEN_SSL
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXSocketOpenSSL.h"
 | 
					#include "IXSocketOpenSSL.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,8 +32,7 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (!systemStore)
 | 
					        if (!systemStore)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            errorMsg = "CertOpenStore failed with ";
 | 
					            errorMsg = "CertOpenStore failed with " errorMsg += std::to_string(GetLastError());
 | 
				
			||||||
            errorMsg += std::to_string(GetLastError());
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,8 +83,6 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    std::atomic<bool> SocketOpenSSL::_openSSLInitializationSuccessful(false);
 | 
					    std::atomic<bool> SocketOpenSSL::_openSSLInitializationSuccessful(false);
 | 
				
			||||||
    std::once_flag SocketOpenSSL::_openSSLInitFlag;
 | 
					    std::once_flag SocketOpenSSL::_openSSLInitFlag;
 | 
				
			||||||
    std::unique_ptr<std::mutex[]> SocketOpenSSL::_openSSLMutexes =
 | 
					 | 
				
			||||||
        std::make_unique<std::mutex[]>(CRYPTO_num_locks());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SocketOpenSSL::SocketOpenSSL(const SocketTLSOptions& tlsOptions, int fd)
 | 
					    SocketOpenSSL::SocketOpenSSL(const SocketTLSOptions& tlsOptions, int fd)
 | 
				
			||||||
        : Socket(fd)
 | 
					        : Socket(fd)
 | 
				
			||||||
@@ -108,11 +104,6 @@ namespace ix
 | 
				
			|||||||
        if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, nullptr)) return;
 | 
					        if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, nullptr)) return;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        (void) OPENSSL_config(nullptr);
 | 
					        (void) OPENSSL_config(nullptr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (CRYPTO_get_locking_callback() == nullptr)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            CRYPTO_set_locking_callback(SocketOpenSSL::openSSLLockingCallback);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (void) OpenSSL_add_ssl_algorithms();
 | 
					        (void) OpenSSL_add_ssl_algorithms();
 | 
				
			||||||
@@ -121,21 +112,6 @@ namespace ix
 | 
				
			|||||||
        _openSSLInitializationSuccessful = true;
 | 
					        _openSSLInitializationSuccessful = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void SocketOpenSSL::openSSLLockingCallback(int mode,
 | 
					 | 
				
			||||||
                                               int type,
 | 
					 | 
				
			||||||
                                               const char* /*file*/,
 | 
					 | 
				
			||||||
                                               int /*line*/)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (mode & CRYPTO_LOCK)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _openSSLMutexes[type].lock();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _openSSLMutexes[type].unlock();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string SocketOpenSSL::getSSLError(int ret)
 | 
					    std::string SocketOpenSSL::getSSLError(int ret)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsigned long e;
 | 
					        unsigned long e;
 | 
				
			||||||
@@ -217,66 +193,6 @@ namespace ix
 | 
				
			|||||||
        return ctx;
 | 
					        return ctx;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketOpenSSL::openSSLAddCARootsFromString(const std::string roots)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Create certificate store
 | 
					 | 
				
			||||||
        X509_STORE* certificate_store = SSL_CTX_get_cert_store(_ssl_context);
 | 
					 | 
				
			||||||
        if (certificate_store == nullptr) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Configure to allow intermediate certs
 | 
					 | 
				
			||||||
        X509_STORE_set_flags(certificate_store,
 | 
					 | 
				
			||||||
                             X509_V_FLAG_TRUSTED_FIRST | X509_V_FLAG_PARTIAL_CHAIN);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Create a new buffer and populate it with the roots
 | 
					 | 
				
			||||||
        BIO* buffer = BIO_new_mem_buf((void*) roots.c_str(), static_cast<int>(roots.length()));
 | 
					 | 
				
			||||||
        if (buffer == nullptr) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Read each root in the buffer and add to the certificate store
 | 
					 | 
				
			||||||
        bool success = true;
 | 
					 | 
				
			||||||
        size_t number_of_roots = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (true)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // Read the next root in the buffer
 | 
					 | 
				
			||||||
            X509* root = PEM_read_bio_X509_AUX(buffer, nullptr, nullptr, (void*) "");
 | 
					 | 
				
			||||||
            if (root == nullptr)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // No more certs left in the buffer, we're done.
 | 
					 | 
				
			||||||
                ERR_clear_error();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Try adding the root to the certificate store
 | 
					 | 
				
			||||||
            ERR_clear_error();
 | 
					 | 
				
			||||||
            if (!X509_STORE_add_cert(certificate_store, root))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // Failed to add. If the error is unrelated to the x509 lib or the cert already
 | 
					 | 
				
			||||||
                // exists, we're safe to continue.
 | 
					 | 
				
			||||||
                unsigned long error = ERR_get_error();
 | 
					 | 
				
			||||||
                if (ERR_GET_LIB(error) != ERR_LIB_X509 ||
 | 
					 | 
				
			||||||
                    ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    // Failed. Clean up and bail.
 | 
					 | 
				
			||||||
                    success = false;
 | 
					 | 
				
			||||||
                    X509_free(root);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Clean up and loop
 | 
					 | 
				
			||||||
            X509_free(root);
 | 
					 | 
				
			||||||
            number_of_roots++;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Clean up buffer
 | 
					 | 
				
			||||||
        BIO_free(buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Make sure we loaded at least one certificate.
 | 
					 | 
				
			||||||
        if (number_of_roots == 0) success = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return success;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Check whether a hostname matches a pattern
 | 
					     * Check whether a hostname matches a pattern
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -471,7 +387,7 @@ namespace ix
 | 
				
			|||||||
            if (_tlsOptions.isUsingSystemDefaults())
 | 
					            if (_tlsOptions.isUsingSystemDefaults())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
                if (!loadWindowsSystemCertificates(_ssl_context, errMsg))
 | 
					                if (!loadWindowsSystemCertificates(_ssl_context))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    return false;
 | 
					                    return false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -485,33 +401,21 @@ namespace ix
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else if (SSL_CTX_load_verify_locations(
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (_tlsOptions.isUsingInMemoryCAs())
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    // Load from memory
 | 
					 | 
				
			||||||
                    openSSLAddCARootsFromString(_tlsOptions.caFile);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (SSL_CTX_load_verify_locations(
 | 
					 | 
				
			||||||
                         _ssl_context, _tlsOptions.caFile.c_str(), NULL) != 1)
 | 
					                         _ssl_context, _tlsOptions.caFile.c_str(), NULL) != 1)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                auto sslErr = ERR_get_error();
 | 
					                auto sslErr = ERR_get_error();
 | 
				
			||||||
                        errMsg = "OpenSSL failed - SSL_CTX_load_verify_locations(\"" +
 | 
					                errMsg = "OpenSSL failed - SSL_CTX_load_verify_locations(\"" + _tlsOptions.caFile +
 | 
				
			||||||
                                 _tlsOptions.caFile + "\") failed: ";
 | 
					                         "\") failed: ";
 | 
				
			||||||
                errMsg += ERR_error_string(sslErr, nullptr);
 | 
					                errMsg += ERR_error_string(sslErr, nullptr);
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    SSL_CTX_set_verify(
 | 
					            SSL_CTX_set_verify(_ssl_context,
 | 
				
			||||||
                        _ssl_context, SSL_VERIFY_PEER, [](int preverify, X509_STORE_CTX*) -> int {
 | 
					                               SSL_VERIFY_PEER,
 | 
				
			||||||
                            return preverify;
 | 
					                               [](int preverify, X509_STORE_CTX*) -> int { return preverify; });
 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
            SSL_CTX_set_verify_depth(_ssl_context, 4);
 | 
					            SSL_CTX_set_verify_depth(_ssl_context, 4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SSL_CTX_set_verify(_ssl_context, SSL_VERIFY_NONE, nullptr);
 | 
					            SSL_CTX_set_verify(_ssl_context, SSL_VERIFY_NONE, nullptr);
 | 
				
			||||||
@@ -619,13 +523,6 @@ namespace ix
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (_tlsOptions.isUsingInMemoryCAs())
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        // Load from memory
 | 
					 | 
				
			||||||
                        openSSLAddCARootsFromString(_tlsOptions.caFile);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    const char* root_ca_file = _tlsOptions.caFile.c_str();
 | 
					                    const char* root_ca_file = _tlsOptions.caFile.c_str();
 | 
				
			||||||
                    STACK_OF(X509_NAME) * rootCAs;
 | 
					                    STACK_OF(X509_NAME) * rootCAs;
 | 
				
			||||||
@@ -633,15 +530,14 @@ namespace ix
 | 
				
			|||||||
                    if (rootCAs == NULL)
 | 
					                    if (rootCAs == NULL)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        auto sslErr = ERR_get_error();
 | 
					                        auto sslErr = ERR_get_error();
 | 
				
			||||||
                            errMsg = "OpenSSL failed - SSL_load_client_CA_file('" +
 | 
					                        errMsg = "OpenSSL failed - SSL_load_client_CA_file('" + _tlsOptions.caFile +
 | 
				
			||||||
                                     _tlsOptions.caFile + "') failed: ";
 | 
					                                 "') failed: ";
 | 
				
			||||||
                        errMsg += ERR_error_string(sslErr, nullptr);
 | 
					                        errMsg += ERR_error_string(sslErr, nullptr);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        SSL_CTX_set_client_CA_list(_ssl_context, rootCAs);
 | 
					                        SSL_CTX_set_client_CA_list(_ssl_context, rootCAs);
 | 
				
			||||||
                            if (SSL_CTX_load_verify_locations(
 | 
					                        if (SSL_CTX_load_verify_locations(_ssl_context, root_ca_file, nullptr) != 1)
 | 
				
			||||||
                                    _ssl_context, root_ca_file, nullptr) != 1)
 | 
					 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            auto sslErr = ERR_get_error();
 | 
					                            auto sslErr = ERR_get_error();
 | 
				
			||||||
                            errMsg = "OpenSSL failed - SSL_CTX_load_verify_locations(\"" +
 | 
					                            errMsg = "OpenSSL failed - SSL_CTX_load_verify_locations(\"" +
 | 
				
			||||||
@@ -650,7 +546,6 @@ namespace ix
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                SSL_CTX_set_verify(
 | 
					                SSL_CTX_set_verify(
 | 
				
			||||||
                    _ssl_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
 | 
					                    _ssl_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
 | 
				
			||||||
@@ -835,5 +730,3 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // IXWEBSOCKET_USE_OPEN_SSL
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 *  IXSocketOpenSSL.h
 | 
					 *  IXSocketOpenSSL.h
 | 
				
			||||||
 *  Author: Benjamin Sergeant, Matt DeBoer
 | 
					 *  Author: Benjamin Sergeant, Matt DeBoer
 | 
				
			||||||
 *  Copyright (c) 2017-2020 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_OPEN_SSL
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,7 +39,6 @@ namespace ix
 | 
				
			|||||||
        void openSSLInitialize();
 | 
					        void openSSLInitialize();
 | 
				
			||||||
        std::string getSSLError(int ret);
 | 
					        std::string getSSLError(int ret);
 | 
				
			||||||
        SSL_CTX* openSSLCreateContext(std::string& errMsg);
 | 
					        SSL_CTX* openSSLCreateContext(std::string& errMsg);
 | 
				
			||||||
        bool openSSLAddCARootsFromString(const std::string roots);
 | 
					 | 
				
			||||||
        bool openSSLClientHandshake(const std::string& hostname,
 | 
					        bool openSSLClientHandshake(const std::string& hostname,
 | 
				
			||||||
                                    std::string& errMsg,
 | 
					                                    std::string& errMsg,
 | 
				
			||||||
                                    const CancellationRequest& isCancellationRequested);
 | 
					                                    const CancellationRequest& isCancellationRequested);
 | 
				
			||||||
@@ -49,9 +47,6 @@ namespace ix
 | 
				
			|||||||
        bool handleTLSOptions(std::string& errMsg);
 | 
					        bool handleTLSOptions(std::string& errMsg);
 | 
				
			||||||
        bool openSSLServerHandshake(std::string& errMsg);
 | 
					        bool openSSLServerHandshake(std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Required for OpenSSL < 1.1
 | 
					 | 
				
			||||||
        static void openSSLLockingCallback(int mode, int type, const char* /*file*/, int /*line*/);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        SSL* _ssl_connection;
 | 
					        SSL* _ssl_connection;
 | 
				
			||||||
        SSL_CTX* _ssl_context;
 | 
					        SSL_CTX* _ssl_context;
 | 
				
			||||||
        const SSL_METHOD* _ssl_method;
 | 
					        const SSL_METHOD* _ssl_method;
 | 
				
			||||||
@@ -61,9 +56,6 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        static std::once_flag _openSSLInitFlag;
 | 
					        static std::once_flag _openSSLInitFlag;
 | 
				
			||||||
        static std::atomic<bool> _openSSLInitializationSuccessful;
 | 
					        static std::atomic<bool> _openSSLInitializationSuccessful;
 | 
				
			||||||
        static std::unique_ptr<std::mutex[]> _openSSLMutexes;
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // IXWEBSOCKET_USE_OPEN_SSL
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,6 @@ namespace ix
 | 
				
			|||||||
    const char* kTLSCAFileUseSystemDefaults = "SYSTEM";
 | 
					    const char* kTLSCAFileUseSystemDefaults = "SYSTEM";
 | 
				
			||||||
    const char* kTLSCAFileDisableVerify = "NONE";
 | 
					    const char* kTLSCAFileDisableVerify = "NONE";
 | 
				
			||||||
    const char* kTLSCiphersUseDefault = "DEFAULT";
 | 
					    const char* kTLSCiphersUseDefault = "DEFAULT";
 | 
				
			||||||
    const char* kTLSInMemoryMarker = "-----BEGIN CERTIFICATE-----";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketTLSOptions::isValid() const
 | 
					    bool SocketTLSOptions::isValid() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -59,11 +58,6 @@ namespace ix
 | 
				
			|||||||
        return caFile == kTLSCAFileUseSystemDefaults;
 | 
					        return caFile == kTLSCAFileUseSystemDefaults;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketTLSOptions::isUsingInMemoryCAs() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return caFile.find(kTLSInMemoryMarker) != std::string::npos;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool SocketTLSOptions::isPeerVerifyDisabled() const
 | 
					    bool SocketTLSOptions::isPeerVerifyDisabled() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return caFile == kTLSCAFileDisableVerify;
 | 
					        return caFile == kTLSCAFileDisableVerify;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,8 +37,6 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        bool isUsingSystemDefaults() const;
 | 
					        bool isUsingSystemDefaults() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool isUsingInMemoryCAs() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool isPeerVerifyDisabled() const;
 | 
					        bool isPeerVerifyDisabled() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool isUsingDefaultCiphers() const;
 | 
					        bool isUsingDefaultCiphers() const;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,18 +44,6 @@ namespace ix
 | 
				
			|||||||
        return err;
 | 
					        return err;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool UdpSocket::isWaitNeeded()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int err = getErrno();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void UdpSocket::closeSocket(int fd)
 | 
					    void UdpSocket::closeSocket(int fd)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
@@ -74,13 +62,6 @@ namespace ix
 | 
				
			|||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
        unsigned long nonblocking = 1;
 | 
					 | 
				
			||||||
        ioctlsocket(_sockfd, FIONBIO, &nonblocking);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        fcntl(_sockfd, F_SETFL, O_NONBLOCK); // make socket non blocking
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        memset(&_server, 0, sizeof(_server));
 | 
					        memset(&_server, 0, sizeof(_server));
 | 
				
			||||||
        _server.sin_family = AF_INET;
 | 
					        _server.sin_family = AF_INET;
 | 
				
			||||||
        _server.sin_port = htons(port);
 | 
					        _server.sin_port = htons(port);
 | 
				
			||||||
@@ -112,15 +93,4 @@ namespace ix
 | 
				
			|||||||
        return (ssize_t)::sendto(
 | 
					        return (ssize_t)::sendto(
 | 
				
			||||||
            _sockfd, buffer.data(), buffer.size(), 0, (struct sockaddr*) &_server, sizeof(_server));
 | 
					            _sockfd, buffer.data(), buffer.size(), 0, (struct sockaddr*) &_server, sizeof(_server));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ssize_t UdpSocket::recvfrom(char* buffer, size_t length)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
        int addressLen = (int) sizeof(_server);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        socklen_t addressLen = (socklen_t) sizeof(_server);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
        return (ssize_t)::recvfrom(
 | 
					 | 
				
			||||||
            _sockfd, buffer, length, 0, (struct sockaddr*) &_server, &addressLen);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,12 +28,9 @@ namespace ix
 | 
				
			|||||||
        // Virtual methods
 | 
					        // Virtual methods
 | 
				
			||||||
        bool init(const std::string& host, int port, std::string& errMsg);
 | 
					        bool init(const std::string& host, int port, std::string& errMsg);
 | 
				
			||||||
        ssize_t sendto(const std::string& buffer);
 | 
					        ssize_t sendto(const std::string& buffer);
 | 
				
			||||||
        ssize_t recvfrom(char* buffer, size_t length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void close();
 | 
					        void close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static int getErrno();
 | 
					        static int getErrno();
 | 
				
			||||||
        static bool isWaitNeeded();
 | 
					 | 
				
			||||||
        static void closeSocket(int fd);
 | 
					        static void closeSocket(int fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +1,4 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Lightweight URL & URI parser (RFC 1738, RFC 3986)
 | 
					 | 
				
			||||||
 * https://github.com/corporateshark/LUrlParser
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The MIT License (MIT)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
 * in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
 * furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in all
 | 
					 | 
				
			||||||
 * copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
					 | 
				
			||||||
 * SOFTWARE.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  IXUrlParser.cpp
 | 
					 *  IXUrlParser.cpp
 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 *  Author: Benjamin Sergeant
 | 
				
			||||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
					 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
@@ -31,308 +6,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXUrlParser.h"
 | 
					#include "IXUrlParser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include "LUrlParser.h"
 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    enum LUrlParserError
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        LUrlParserError_Ok = 0,
 | 
					 | 
				
			||||||
        LUrlParserError_Uninitialized = 1,
 | 
					 | 
				
			||||||
        LUrlParserError_NoUrlCharacter = 2,
 | 
					 | 
				
			||||||
        LUrlParserError_InvalidSchemeName = 3,
 | 
					 | 
				
			||||||
        LUrlParserError_NoDoubleSlash = 4,
 | 
					 | 
				
			||||||
        LUrlParserError_NoAtSign = 5,
 | 
					 | 
				
			||||||
        LUrlParserError_UnexpectedEndOfLine = 6,
 | 
					 | 
				
			||||||
        LUrlParserError_NoSlash = 7,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class clParseURL
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        LUrlParserError m_ErrorCode;
 | 
					 | 
				
			||||||
        std::string m_Scheme;
 | 
					 | 
				
			||||||
        std::string m_Host;
 | 
					 | 
				
			||||||
        std::string m_Port;
 | 
					 | 
				
			||||||
        std::string m_Path;
 | 
					 | 
				
			||||||
        std::string m_Query;
 | 
					 | 
				
			||||||
        std::string m_Fragment;
 | 
					 | 
				
			||||||
        std::string m_UserName;
 | 
					 | 
				
			||||||
        std::string m_Password;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        clParseURL()
 | 
					 | 
				
			||||||
            : m_ErrorCode(LUrlParserError_Uninitialized)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// return 'true' if the parsing was successful
 | 
					 | 
				
			||||||
        bool IsValid() const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return m_ErrorCode == LUrlParserError_Ok;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// helper to convert the port number to int, return 'true' if the port is valid (within the
 | 
					 | 
				
			||||||
        /// 0..65535 range)
 | 
					 | 
				
			||||||
        bool GetPort(int* OutPort) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// parse the URL
 | 
					 | 
				
			||||||
        static clParseURL ParseURL(const std::string& URL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					 | 
				
			||||||
        explicit clParseURL(LUrlParserError ErrorCode)
 | 
					 | 
				
			||||||
            : m_ErrorCode(ErrorCode)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static bool IsSchemeValid(const std::string& SchemeName)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        for (auto c : SchemeName)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (!isalpha(c) && c != '+' && c != '-' && c != '.') return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool clParseURL::GetPort(int* OutPort) const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (!IsValid())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int Port = atoi(m_Port.c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (Port <= 0 || Port > 65535)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (OutPort)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            *OutPort = Port;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // based on RFC 1738 and RFC 3986
 | 
					 | 
				
			||||||
    clParseURL clParseURL::ParseURL(const std::string& URL)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        clParseURL Result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const char* CurrentString = URL.c_str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
         *	<scheme>:<scheme-specific-part>
 | 
					 | 
				
			||||||
         *	<scheme> := [a-z\+\-\.]+
 | 
					 | 
				
			||||||
         *	For resiliency, programs interpreting URLs should treat upper case letters as
 | 
					 | 
				
			||||||
         *equivalent to lower case in scheme names
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // try to read scheme
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            const char* LocalString = strchr(CurrentString, ':');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!LocalString)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return clParseURL(LUrlParserError_NoUrlCharacter);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // save the scheme name
 | 
					 | 
				
			||||||
            Result.m_Scheme = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!IsSchemeValid(Result.m_Scheme))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return clParseURL(LUrlParserError_InvalidSchemeName);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // scheme should be lowercase
 | 
					 | 
				
			||||||
            std::transform(
 | 
					 | 
				
			||||||
                Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // skip ':'
 | 
					 | 
				
			||||||
            CurrentString = LocalString + 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
         *	//<user>:<password>@<host>:<port>/<url-path>
 | 
					 | 
				
			||||||
         *	any ":", "@" and "/" must be normalized
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // skip "//"
 | 
					 | 
				
			||||||
        if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
 | 
					 | 
				
			||||||
        if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // check if the user name and password are specified
 | 
					 | 
				
			||||||
        bool bHasUserName = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const char* LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (*LocalString)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (*LocalString == '@')
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // user name and password are specified
 | 
					 | 
				
			||||||
                bHasUserName = true;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (*LocalString == '/')
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // end of <host>:<port> specification
 | 
					 | 
				
			||||||
                bHasUserName = false;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            LocalString++;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // user name and password
 | 
					 | 
				
			||||||
        LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (bHasUserName)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // read user name
 | 
					 | 
				
			||||||
            while (*LocalString && *LocalString != ':' && *LocalString != '@')
 | 
					 | 
				
			||||||
                LocalString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Result.m_UserName = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // proceed with the current pointer
 | 
					 | 
				
			||||||
            CurrentString = LocalString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (*CurrentString == ':')
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // skip ':'
 | 
					 | 
				
			||||||
                CurrentString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // read password
 | 
					 | 
				
			||||||
                LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                while (*LocalString && *LocalString != '@')
 | 
					 | 
				
			||||||
                    LocalString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Result.m_Password = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                CurrentString = LocalString;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // skip '@'
 | 
					 | 
				
			||||||
            if (*CurrentString != '@')
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return clParseURL(LUrlParserError_NoAtSign);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CurrentString++;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool bHasBracket = (*CurrentString == '[');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // go ahead, read the host name
 | 
					 | 
				
			||||||
        LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (*LocalString)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (bHasBracket && *LocalString == ']')
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // end of IPv6 address
 | 
					 | 
				
			||||||
                LocalString++;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/'))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // port number is specified
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            LocalString++;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Result.m_Host = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CurrentString = LocalString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // is port number specified?
 | 
					 | 
				
			||||||
        if (*CurrentString == ':')
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            CurrentString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // read port number
 | 
					 | 
				
			||||||
            LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while (*LocalString && *LocalString != '/')
 | 
					 | 
				
			||||||
                LocalString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Result.m_Port = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CurrentString = LocalString;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // end of string
 | 
					 | 
				
			||||||
        if (!*CurrentString)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Result.m_ErrorCode = LUrlParserError_Ok;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return Result;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // skip '/'
 | 
					 | 
				
			||||||
        if (*CurrentString != '/')
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return clParseURL(LUrlParserError_NoSlash);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CurrentString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // parse the path
 | 
					 | 
				
			||||||
        LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (*LocalString && *LocalString != '#' && *LocalString != '?')
 | 
					 | 
				
			||||||
            LocalString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Result.m_Path = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CurrentString = LocalString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // check for query
 | 
					 | 
				
			||||||
        if (*CurrentString == '?')
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // skip '?'
 | 
					 | 
				
			||||||
            CurrentString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // read query
 | 
					 | 
				
			||||||
            LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while (*LocalString && *LocalString != '#')
 | 
					 | 
				
			||||||
                LocalString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Result.m_Query = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CurrentString = LocalString;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // check for fragment
 | 
					 | 
				
			||||||
        if (*CurrentString == '#')
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // skip '#'
 | 
					 | 
				
			||||||
            CurrentString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // read fragment
 | 
					 | 
				
			||||||
            LocalString = CurrentString;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while (*LocalString)
 | 
					 | 
				
			||||||
                LocalString++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Result.m_Fragment = std::string(CurrentString, LocalString - CurrentString);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Result.m_ErrorCode = LUrlParserError_Ok;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return Result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
} // namespace
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -343,7 +17,7 @@ namespace ix
 | 
				
			|||||||
                          std::string& query,
 | 
					                          std::string& query,
 | 
				
			||||||
                          int& port)
 | 
					                          int& port)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        clParseURL res = clParseURL::ParseURL(url);
 | 
					        LUrlParser::clParseURL res = LUrlParser::clParseURL::ParseURL(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!res.IsValid())
 | 
					        if (!res.IsValid())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ namespace ix
 | 
				
			|||||||
        _ws.setOnCloseCallback(
 | 
					        _ws.setOnCloseCallback(
 | 
				
			||||||
            [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) {
 | 
					            [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) {
 | 
				
			||||||
                _onMessageCallback(
 | 
					                _onMessageCallback(
 | 
				
			||||||
                    std::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
 | 
					                    std::make_shared<WebSocketMessage>(WebSocketMessageType::Close,
 | 
				
			||||||
                                                       "",
 | 
					                                                       "",
 | 
				
			||||||
                                                       wireSize,
 | 
					                                                       wireSize,
 | 
				
			||||||
                                                       WebSocketErrorInfo(),
 | 
					                                                       WebSocketErrorInfo(),
 | 
				
			||||||
@@ -193,7 +193,7 @@ namespace ix
 | 
				
			|||||||
            return status;
 | 
					            return status;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _onMessageCallback(std::make_unique<WebSocketMessage>(
 | 
					        _onMessageCallback(std::make_shared<WebSocketMessage>(
 | 
				
			||||||
            WebSocketMessageType::Open,
 | 
					            WebSocketMessageType::Open,
 | 
				
			||||||
            "",
 | 
					            "",
 | 
				
			||||||
            0,
 | 
					            0,
 | 
				
			||||||
@@ -225,7 +225,7 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _onMessageCallback(
 | 
					        _onMessageCallback(
 | 
				
			||||||
            std::make_unique<WebSocketMessage>(WebSocketMessageType::Open,
 | 
					            std::make_shared<WebSocketMessage>(WebSocketMessageType::Open,
 | 
				
			||||||
                                               "",
 | 
					                                               "",
 | 
				
			||||||
                                               0,
 | 
					                                               0,
 | 
				
			||||||
                                               WebSocketErrorInfo(),
 | 
					                                               WebSocketErrorInfo(),
 | 
				
			||||||
@@ -310,7 +310,7 @@ namespace ix
 | 
				
			|||||||
                connectErr.reason = status.errorStr;
 | 
					                connectErr.reason = status.errorStr;
 | 
				
			||||||
                connectErr.http_status = status.http_status;
 | 
					                connectErr.http_status = status.http_status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _onMessageCallback(std::make_unique<WebSocketMessage>(WebSocketMessageType::Error,
 | 
					                _onMessageCallback(std::make_shared<WebSocketMessage>(WebSocketMessageType::Error,
 | 
				
			||||||
                                                                      "",
 | 
					                                                                      "",
 | 
				
			||||||
                                                                      0,
 | 
					                                                                      0,
 | 
				
			||||||
                                                                      connectErr,
 | 
					                                                                      connectErr,
 | 
				
			||||||
@@ -386,7 +386,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    bool binary = messageKind == WebSocketTransport::MessageKind::MSG_BINARY;
 | 
					                    bool binary = messageKind == WebSocketTransport::MessageKind::MSG_BINARY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    _onMessageCallback(std::make_unique<WebSocketMessage>(webSocketMessageType,
 | 
					                    _onMessageCallback(std::make_shared<WebSocketMessage>(webSocketMessageType,
 | 
				
			||||||
                                                                          msg,
 | 
					                                                                          msg,
 | 
				
			||||||
                                                                          wireSize,
 | 
					                                                                          wireSize,
 | 
				
			||||||
                                                                          webSocketErrorInfo,
 | 
					                                                                          webSocketErrorInfo,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct WebSocketCloseInfo
 | 
					    struct WebSocketCloseInfo
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
#include "IXSocketConnect.h"
 | 
					#include "IXSocketConnect.h"
 | 
				
			||||||
#include "IXUrlParser.h"
 | 
					#include "IXUrlParser.h"
 | 
				
			||||||
#include "IXUserAgent.h"
 | 
					#include "IXUserAgent.h"
 | 
				
			||||||
#include "IXWebSocketHandshakeKeyGen.h"
 | 
					#include "libwshandshake.hpp"
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <random>
 | 
					#include <random>
 | 
				
			||||||
@@ -133,7 +133,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        for (auto& it : extraHeaders)
 | 
					        for (auto& it : extraHeaders)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ss << it.first << ": " << it.second << "\r\n";
 | 
					            ss << it.first << ":" << it.second << "\r\n";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (_enablePerMessageDeflate)
 | 
					        if (_enablePerMessageDeflate)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,171 +0,0 @@
 | 
				
			|||||||
// Copyright (c) 2016 Alex Hultman and contributors
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// This software is provided 'as-is', without any express or implied
 | 
					 | 
				
			||||||
// warranty. In no event will the authors be held liable for any damages
 | 
					 | 
				
			||||||
// arising from the use of this software.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Permission is granted to anyone to use this software for any purpose,
 | 
					 | 
				
			||||||
// including commercial applications, and to alter it and redistribute it
 | 
					 | 
				
			||||||
// freely, subject to the following restrictions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 1. The origin of this software must not be misrepresented; you must not
 | 
					 | 
				
			||||||
//    claim that you wrote the original software. If you use this software
 | 
					 | 
				
			||||||
//    in a product, an acknowledgement in the product documentation would be
 | 
					 | 
				
			||||||
//    appreciated but is not required.
 | 
					 | 
				
			||||||
// 2. Altered source versions must be plainly marked as such, and must not be
 | 
					 | 
				
			||||||
//    misrepresented as being the original software.
 | 
					 | 
				
			||||||
// 3. This notice may not be removed or altered from any source distribution.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cstddef>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class WebSocketHandshakeKeyGen
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    template<int N, typename T>
 | 
					 | 
				
			||||||
    struct static_for
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        void operator()(uint32_t* a, uint32_t* b)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            static_for<N - 1, T>()(a, b);
 | 
					 | 
				
			||||||
            T::template f<N - 1>(a, b);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template<typename T>
 | 
					 | 
				
			||||||
    struct static_for<0, T>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        void operator()(uint32_t* /*a*/, uint32_t* /*hash*/)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template<int state>
 | 
					 | 
				
			||||||
    struct Sha1Loop
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        static inline uint32_t rol(uint32_t value, size_t bits)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return (value << bits) | (value >> (32 - bits));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        static inline uint32_t blk(uint32_t b[16], size_t i)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        template<int i>
 | 
					 | 
				
			||||||
        static inline void f(uint32_t* a, uint32_t* b)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            switch (state)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case 1:
 | 
					 | 
				
			||||||
                    a[i % 5] +=
 | 
					 | 
				
			||||||
                        ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) +
 | 
					 | 
				
			||||||
                        b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5);
 | 
					 | 
				
			||||||
                    a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case 2:
 | 
					 | 
				
			||||||
                    b[i] = blk(b, i);
 | 
					 | 
				
			||||||
                    a[(1 + i) % 5] +=
 | 
					 | 
				
			||||||
                        ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) +
 | 
					 | 
				
			||||||
                        b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5);
 | 
					 | 
				
			||||||
                    a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case 3:
 | 
					 | 
				
			||||||
                    b[(i + 4) % 16] = blk(b, (i + 4) % 16);
 | 
					 | 
				
			||||||
                    a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) +
 | 
					 | 
				
			||||||
                                b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5);
 | 
					 | 
				
			||||||
                    a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case 4:
 | 
					 | 
				
			||||||
                    b[(i + 8) % 16] = blk(b, (i + 8) % 16);
 | 
					 | 
				
			||||||
                    a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) |
 | 
					 | 
				
			||||||
                                 (a[(3 + i) % 5] & a[(2 + i) % 5])) +
 | 
					 | 
				
			||||||
                                b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5);
 | 
					 | 
				
			||||||
                    a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case 5:
 | 
					 | 
				
			||||||
                    b[(i + 12) % 16] = blk(b, (i + 12) % 16);
 | 
					 | 
				
			||||||
                    a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) +
 | 
					 | 
				
			||||||
                                b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5);
 | 
					 | 
				
			||||||
                    a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case 6: b[i] += a[4 - i];
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static inline void sha1(uint32_t hash[5], uint32_t b[16])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]};
 | 
					 | 
				
			||||||
        static_for<16, Sha1Loop<1>>()(a, b);
 | 
					 | 
				
			||||||
        static_for<4, Sha1Loop<2>>()(a, b);
 | 
					 | 
				
			||||||
        static_for<20, Sha1Loop<3>>()(a, b);
 | 
					 | 
				
			||||||
        static_for<20, Sha1Loop<4>>()(a, b);
 | 
					 | 
				
			||||||
        static_for<20, Sha1Loop<5>>()(a, b);
 | 
					 | 
				
			||||||
        static_for<5, Sha1Loop<6>>()(a, hash);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static inline void base64(unsigned char* src, char* dst)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        const char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
					 | 
				
			||||||
        for (int i = 0; i < 18; i += 3)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            *dst++ = b64[(src[i] >> 2) & 63];
 | 
					 | 
				
			||||||
            *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)];
 | 
					 | 
				
			||||||
            *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)];
 | 
					 | 
				
			||||||
            *dst++ = b64[src[i + 2] & 63];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        *dst++ = b64[(src[18] >> 2) & 63];
 | 
					 | 
				
			||||||
        *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)];
 | 
					 | 
				
			||||||
        *dst++ = b64[((src[19] & 15) << 2)];
 | 
					 | 
				
			||||||
        *dst++ = '=';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    static inline void generate(const std::string& inputStr, char output[28])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        char input[25] = {};
 | 
					 | 
				
			||||||
        strncpy(input, inputStr.c_str(), 25 - 1);
 | 
					 | 
				
			||||||
        input[25 - 1] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint32_t b_output[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0};
 | 
					 | 
				
			||||||
        uint32_t b_input[16] = {0,
 | 
					 | 
				
			||||||
                                0,
 | 
					 | 
				
			||||||
                                0,
 | 
					 | 
				
			||||||
                                0,
 | 
					 | 
				
			||||||
                                0,
 | 
					 | 
				
			||||||
                                0,
 | 
					 | 
				
			||||||
                                0x32353845,
 | 
					 | 
				
			||||||
                                0x41464135,
 | 
					 | 
				
			||||||
                                0x2d453931,
 | 
					 | 
				
			||||||
                                0x342d3437,
 | 
					 | 
				
			||||||
                                0x44412d39,
 | 
					 | 
				
			||||||
                                0x3543412d,
 | 
					 | 
				
			||||||
                                0x43354142,
 | 
					 | 
				
			||||||
                                0x30444338,
 | 
					 | 
				
			||||||
                                0x35423131,
 | 
					 | 
				
			||||||
                                0x80000000};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (int i = 0; i < 6; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            b_input[i] = (input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 |
 | 
					 | 
				
			||||||
                         (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        sha1(b_output, b_input);
 | 
					 | 
				
			||||||
        uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480};
 | 
					 | 
				
			||||||
        sha1(b_output, last_b);
 | 
					 | 
				
			||||||
        for (int i = 0; i < 5; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            uint32_t tmp = b_output[i];
 | 
					 | 
				
			||||||
            char* bytes = (char*) &b_output[i];
 | 
					 | 
				
			||||||
            bytes[3] = tmp & 0xff;
 | 
					 | 
				
			||||||
            bytes[2] = (tmp >> 8) & 0xff;
 | 
					 | 
				
			||||||
            bytes[1] = (tmp >> 16) & 0xff;
 | 
					 | 
				
			||||||
            bytes[0] = (tmp >> 24) & 0xff;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        base64((unsigned char*) b_output, output);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -19,7 +19,7 @@ namespace ix
 | 
				
			|||||||
    struct WebSocketMessage
 | 
					    struct WebSocketMessage
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        WebSocketMessageType type;
 | 
					        WebSocketMessageType type;
 | 
				
			||||||
        const std::string& str;
 | 
					        std::string str;
 | 
				
			||||||
        size_t wireSize;
 | 
					        size_t wireSize;
 | 
				
			||||||
        WebSocketErrorInfo errorInfo;
 | 
					        WebSocketErrorInfo errorInfo;
 | 
				
			||||||
        WebSocketOpenInfo openInfo;
 | 
					        WebSocketOpenInfo openInfo;
 | 
				
			||||||
@@ -34,7 +34,7 @@ namespace ix
 | 
				
			|||||||
                         WebSocketCloseInfo c,
 | 
					                         WebSocketCloseInfo c,
 | 
				
			||||||
                         bool b = false)
 | 
					                         bool b = false)
 | 
				
			||||||
            : type(t)
 | 
					            : type(t)
 | 
				
			||||||
            , str(s)
 | 
					            , str(std::move(s))
 | 
				
			||||||
            , wireSize(w)
 | 
					            , wireSize(w)
 | 
				
			||||||
            , errorInfo(e)
 | 
					            , errorInfo(e)
 | 
				
			||||||
            , openInfo(o)
 | 
					            , openInfo(o)
 | 
				
			||||||
@@ -45,5 +45,5 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using WebSocketMessagePtr = std::unique_ptr<WebSocketMessage>;
 | 
					    using WebSocketMessagePtr = std::shared_ptr<WebSocketMessage>;
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										86
									
								
								ixwebsocket/IXWebSocketMessageQueue.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								ixwebsocket/IXWebSocketMessageQueue.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXWebSocketMessageQueue.cpp
 | 
				
			||||||
 | 
					 *  Author: Korchynskyi Dmytro
 | 
				
			||||||
 | 
					 *  Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXWebSocketMessageQueue.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WebSocketMessageQueue::WebSocketMessageQueue(WebSocket* websocket)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        bindWebsocket(websocket);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WebSocketMessageQueue::~WebSocketMessageQueue()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!_messages.empty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // not handled all messages
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bindWebsocket(nullptr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketMessageQueue::bindWebsocket(WebSocket* websocket)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (_websocket == websocket) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // unbind old
 | 
				
			||||||
 | 
					        if (_websocket)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // set dummy callback just to avoid crash
 | 
				
			||||||
 | 
					            _websocket->setOnMessageCallback([](const WebSocketMessagePtr&) {});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _websocket = websocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // bind new
 | 
				
			||||||
 | 
					        if (_websocket)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _websocket->setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
 | 
				
			||||||
 | 
					                std::lock_guard<std::mutex> lock(_messagesMutex);
 | 
				
			||||||
 | 
					                _messages.emplace_back(std::move(msg));
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketMessageQueue::setOnMessageCallback(const OnMessageCallback& callback)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _onMessageUserCallback = callback;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketMessageQueue::setOnMessageCallback(OnMessageCallback&& callback)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _onMessageUserCallback = std::move(callback);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WebSocketMessagePtr WebSocketMessageQueue::popMessage()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        WebSocketMessagePtr message;
 | 
				
			||||||
 | 
					        std::lock_guard<std::mutex> lock(_messagesMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!_messages.empty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            message = std::move(_messages.front());
 | 
				
			||||||
 | 
					            _messages.pop_front();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return message;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocketMessageQueue::poll(int count)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!_onMessageUserCallback) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        WebSocketMessagePtr message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (count > 0 && (message = popMessage()))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _onMessageUserCallback(message);
 | 
				
			||||||
 | 
					            --count;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ix
 | 
				
			||||||
							
								
								
									
										41
									
								
								ixwebsocket/IXWebSocketMessageQueue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								ixwebsocket/IXWebSocketMessageQueue.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXWebSocketMessageQueue.h
 | 
				
			||||||
 | 
					 *  Author: Korchynskyi Dmytro
 | 
				
			||||||
 | 
					 *  Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXWebSocket.h"
 | 
				
			||||||
 | 
					#include <list>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace ix
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // A helper class to dispatch websocket message callbacks in your thread.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    class WebSocketMessageQueue
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        WebSocketMessageQueue(WebSocket* websocket = nullptr);
 | 
				
			||||||
 | 
					        ~WebSocketMessageQueue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void bindWebsocket(WebSocket* websocket);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void setOnMessageCallback(const OnMessageCallback& callback);
 | 
				
			||||||
 | 
					        void setOnMessageCallback(OnMessageCallback&& callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void poll(int count = 512);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected:
 | 
				
			||||||
 | 
					        WebSocketMessagePtr popMessage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        WebSocket* _websocket = nullptr;
 | 
				
			||||||
 | 
					        OnMessageCallback _onMessageUserCallback;
 | 
				
			||||||
 | 
					        std::mutex _messagesMutex;
 | 
				
			||||||
 | 
					        std::list<WebSocketMessagePtr> _messages;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					} // namespace ix
 | 
				
			||||||
@@ -6,10 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct WebSocketOpenInfo
 | 
					    struct WebSocketOpenInfo
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,9 +87,6 @@ namespace ix
 | 
				
			|||||||
        //
 | 
					        //
 | 
				
			||||||
        size_t output;
 | 
					        size_t output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Clear output
 | 
					 | 
				
			||||||
        out.clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (in.empty())
 | 
					        if (in.empty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // See issue #167
 | 
					            // See issue #167
 | 
				
			||||||
@@ -177,9 +174,6 @@ namespace ix
 | 
				
			|||||||
        _inflateState.avail_in = (uInt) inFixed.size();
 | 
					        _inflateState.avail_in = (uInt) inFixed.size();
 | 
				
			||||||
        _inflateState.next_in = (unsigned char*) (const_cast<char*>(inFixed.data()));
 | 
					        _inflateState.next_in = (unsigned char*) (const_cast<char*>(inFixed.data()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Clear output
 | 
					 | 
				
			||||||
        out.clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        do
 | 
					        do
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _inflateState.avail_out = (uInt) _compressBufferSize;
 | 
					            _inflateState.avail_out = (uInt) _compressBufferSize;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,7 @@ namespace ix
 | 
				
			|||||||
    WebSocketTransport::WebSocketTransport()
 | 
					    WebSocketTransport::WebSocketTransport()
 | 
				
			||||||
        : _useMask(true)
 | 
					        : _useMask(true)
 | 
				
			||||||
        , _blockingSend(false)
 | 
					        , _blockingSend(false)
 | 
				
			||||||
        , _receivedMessageCompressed(false)
 | 
					        , _compressedMessage(false)
 | 
				
			||||||
        , _readyState(ReadyState::CLOSED)
 | 
					        , _readyState(ReadyState::CLOSED)
 | 
				
			||||||
        , _closeCode(WebSocketCloseConstants::kInternalErrorCode)
 | 
					        , _closeCode(WebSocketCloseConstants::kInternalErrorCode)
 | 
				
			||||||
        , _closeReason(WebSocketCloseConstants::kInternalErrorMessage)
 | 
					        , _closeReason(WebSocketCloseConstants::kInternalErrorMessage)
 | 
				
			||||||
@@ -74,7 +74,6 @@ namespace ix
 | 
				
			|||||||
        , _enablePong(kDefaultEnablePong)
 | 
					        , _enablePong(kDefaultEnablePong)
 | 
				
			||||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
					        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
				
			||||||
        , _pongReceived(false)
 | 
					        , _pongReceived(false)
 | 
				
			||||||
        , _pingCount(0)
 | 
					 | 
				
			||||||
        , _lastSendPingTimePoint(std::chrono::steady_clock::now())
 | 
					        , _lastSendPingTimePoint(std::chrono::steady_clock::now())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _readbuf.resize(kChunkSize);
 | 
					        _readbuf.resize(kChunkSize);
 | 
				
			||||||
@@ -222,8 +221,7 @@ namespace ix
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        _pongReceived = false;
 | 
					        _pongReceived = false;
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << kPingMessage << "::" << _pingIntervalSecs << "s"
 | 
					        ss << kPingMessage << "::" << _pingIntervalSecs << "s";
 | 
				
			||||||
           << "::" << _pingCount++;
 | 
					 | 
				
			||||||
        return sendPing(ss.str());
 | 
					        return sendPing(ss.str());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -495,7 +493,7 @@ namespace ix
 | 
				
			|||||||
                                                 ? MessageKind::MSG_TEXT
 | 
					                                                 ? MessageKind::MSG_TEXT
 | 
				
			||||||
                                                 : MessageKind::MSG_BINARY;
 | 
					                                                 : MessageKind::MSG_BINARY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    _receivedMessageCompressed = _enablePerMessageDeflate && ws.rsv1;
 | 
					                    _compressedMessage = _enablePerMessageDeflate && ws.rsv1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Continuation message needs to follow a non-fin TEXT or BINARY message
 | 
					                    // Continuation message needs to follow a non-fin TEXT or BINARY message
 | 
				
			||||||
                    if (!_chunks.empty())
 | 
					                    if (!_chunks.empty())
 | 
				
			||||||
@@ -517,12 +515,10 @@ namespace ix
 | 
				
			|||||||
                //
 | 
					                //
 | 
				
			||||||
                if (ws.fin && _chunks.empty())
 | 
					                if (ws.fin && _chunks.empty())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    emitMessage(_fragmentedMessageKind,
 | 
					                    emitMessage(
 | 
				
			||||||
                                frameData,
 | 
					                        _fragmentedMessageKind, frameData, _compressedMessage, onMessageCallback);
 | 
				
			||||||
                                _receivedMessageCompressed,
 | 
					 | 
				
			||||||
                                onMessageCallback);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    _receivedMessageCompressed = false;
 | 
					                    _compressedMessage = false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -539,11 +535,11 @@ namespace ix
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        emitMessage(_fragmentedMessageKind,
 | 
					                        emitMessage(_fragmentedMessageKind,
 | 
				
			||||||
                                    getMergedChunks(),
 | 
					                                    getMergedChunks(),
 | 
				
			||||||
                                    _receivedMessageCompressed,
 | 
					                                    _compressedMessage,
 | 
				
			||||||
                                    onMessageCallback);
 | 
					                                    onMessageCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        _chunks.clear();
 | 
					                        _chunks.clear();
 | 
				
			||||||
                        _receivedMessageCompressed = false;
 | 
					                        _compressedMessage = false;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
@@ -716,16 +712,17 @@ namespace ix
 | 
				
			|||||||
        // When the RSV1 bit is 1 it means the message is compressed
 | 
					        // When the RSV1 bit is 1 it means the message is compressed
 | 
				
			||||||
        if (compressedMessage && messageKind != MessageKind::FRAGMENT)
 | 
					        if (compressedMessage && messageKind != MessageKind::FRAGMENT)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            bool success = _perMessageDeflate->decompress(message, _decompressedMessage);
 | 
					            std::string decompressedMessage;
 | 
				
			||||||
 | 
					            bool success = _perMessageDeflate->decompress(message, decompressedMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (messageKind == MessageKind::MSG_TEXT && !validateUtf8(_decompressedMessage))
 | 
					            if (messageKind == MessageKind::MSG_TEXT && !validateUtf8(decompressedMessage))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                close(WebSocketCloseConstants::kInvalidFramePayloadData,
 | 
					                close(WebSocketCloseConstants::kInvalidFramePayloadData,
 | 
				
			||||||
                      WebSocketCloseConstants::kInvalidFramePayloadDataMessage);
 | 
					                      WebSocketCloseConstants::kInvalidFramePayloadDataMessage);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                onMessageCallback(_decompressedMessage, wireSize, !success, messageKind);
 | 
					                onMessageCallback(decompressedMessage, wireSize, !success, messageKind);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
@@ -762,6 +759,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        size_t payloadSize = message.size();
 | 
					        size_t payloadSize = message.size();
 | 
				
			||||||
        size_t wireSize = message.size();
 | 
					        size_t wireSize = message.size();
 | 
				
			||||||
 | 
					        std::string compressedMessage;
 | 
				
			||||||
        bool compressionError = false;
 | 
					        bool compressionError = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string::const_iterator message_begin = message.begin();
 | 
					        std::string::const_iterator message_begin = message.begin();
 | 
				
			||||||
@@ -769,7 +767,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (compress)
 | 
					        if (compress)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!_perMessageDeflate->compress(message, _compressedMessage))
 | 
					            if (!_perMessageDeflate->compress(message, compressedMessage))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                bool success = false;
 | 
					                bool success = false;
 | 
				
			||||||
                compressionError = true;
 | 
					                compressionError = true;
 | 
				
			||||||
@@ -778,10 +776,10 @@ namespace ix
 | 
				
			|||||||
                return WebSocketSendInfo(success, compressionError, payloadSize, wireSize);
 | 
					                return WebSocketSendInfo(success, compressionError, payloadSize, wireSize);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            compressionError = false;
 | 
					            compressionError = false;
 | 
				
			||||||
            wireSize = _compressedMessage.size();
 | 
					            wireSize = compressedMessage.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            message_begin = _compressedMessage.begin();
 | 
					            message_begin = compressedMessage.begin();
 | 
				
			||||||
            message_end = _compressedMessage.end();
 | 
					            message_end = compressedMessage.end();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -165,7 +165,7 @@ namespace ix
 | 
				
			|||||||
        MessageKind _fragmentedMessageKind;
 | 
					        MessageKind _fragmentedMessageKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Ditto for whether a message is compressed
 | 
					        // Ditto for whether a message is compressed
 | 
				
			||||||
        bool _receivedMessageCompressed;
 | 
					        bool _compressedMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Fragments are 32K long
 | 
					        // Fragments are 32K long
 | 
				
			||||||
        static constexpr size_t kChunkSize = 1 << 15;
 | 
					        static constexpr size_t kChunkSize = 1 << 15;
 | 
				
			||||||
@@ -189,9 +189,6 @@ namespace ix
 | 
				
			|||||||
        WebSocketPerMessageDeflateOptions _perMessageDeflateOptions;
 | 
					        WebSocketPerMessageDeflateOptions _perMessageDeflateOptions;
 | 
				
			||||||
        std::atomic<bool> _enablePerMessageDeflate;
 | 
					        std::atomic<bool> _enablePerMessageDeflate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string _decompressedMessage;
 | 
					 | 
				
			||||||
        std::string _compressedMessage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Used to control TLS connection behavior
 | 
					        // Used to control TLS connection behavior
 | 
				
			||||||
        SocketTLSOptions _socketTLSOptions;
 | 
					        SocketTLSOptions _socketTLSOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,7 +209,6 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        static const int kDefaultPingIntervalSecs;
 | 
					        static const int kDefaultPingIntervalSecs;
 | 
				
			||||||
        static const std::string kPingMessage;
 | 
					        static const std::string kPingMessage;
 | 
				
			||||||
        std::atomic<uint64_t> _pingCount;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // We record when ping are being sent so that we can know when to send the next one
 | 
					        // We record when ping are being sent so that we can know when to send the next one
 | 
				
			||||||
        mutable std::mutex _lastSendPingTimePointMutex;
 | 
					        mutable std::mutex _lastSendPingTimePointMutex;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IX_WEBSOCKET_VERSION "9.6.3"
 | 
					#define IX_WEBSOCKET_VERSION "9.2.0"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										280
									
								
								ixwebsocket/LUrlParser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								ixwebsocket/LUrlParser.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,280 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Lightweight URL & URI parser (RFC 1738, RFC 3986)
 | 
				
			||||||
 | 
					 * https://github.com/corporateshark/LUrlParser
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The MIT License (MIT)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					 * of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					 * in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					 * copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					 * furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					 * copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					 * SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "LUrlParser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// check if the scheme name is valid
 | 
				
			||||||
 | 
					static bool IsSchemeValid(const std::string& SchemeName)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (auto c : SchemeName)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!isalpha(c) && c != '+' && c != '-' && c != '.') return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LUrlParser::clParseURL::GetPort(int* OutPort) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!IsValid())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int Port = atoi(m_Port.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (Port <= 0 || Port > 65535)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (OutPort)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        *OutPort = Port;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// based on RFC 1738 and RFC 3986
 | 
				
			||||||
 | 
					LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL(const std::string& URL)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LUrlParser::clParseURL Result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char* CurrentString = URL.c_str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     *	<scheme>:<scheme-specific-part>
 | 
				
			||||||
 | 
					     *	<scheme> := [a-z\+\-\.]+
 | 
				
			||||||
 | 
					     *	For resiliency, programs interpreting URLs should treat upper case letters as equivalent to
 | 
				
			||||||
 | 
					     *lower case in scheme names
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // try to read scheme
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const char* LocalString = strchr(CurrentString, ':');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!LocalString)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return clParseURL(LUrlParserError_NoUrlCharacter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // save the scheme name
 | 
				
			||||||
 | 
					        Result.m_Scheme = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!IsSchemeValid(Result.m_Scheme))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return clParseURL(LUrlParserError_InvalidSchemeName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // scheme should be lowercase
 | 
				
			||||||
 | 
					        std::transform(
 | 
				
			||||||
 | 
					            Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // skip ':'
 | 
				
			||||||
 | 
					        CurrentString = LocalString + 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     *	//<user>:<password>@<host>:<port>/<url-path>
 | 
				
			||||||
 | 
					     *	any ":", "@" and "/" must be normalized
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // skip "//"
 | 
				
			||||||
 | 
					    if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
 | 
				
			||||||
 | 
					    if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // check if the user name and password are specified
 | 
				
			||||||
 | 
					    bool bHasUserName = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char* LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (*LocalString)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (*LocalString == '@')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // user name and password are specified
 | 
				
			||||||
 | 
					            bHasUserName = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (*LocalString == '/')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // end of <host>:<port> specification
 | 
				
			||||||
 | 
					            bHasUserName = false;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LocalString++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // user name and password
 | 
				
			||||||
 | 
					    LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bHasUserName)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // read user name
 | 
				
			||||||
 | 
					        while (*LocalString && *LocalString != ':' && *LocalString != '@')
 | 
				
			||||||
 | 
					            LocalString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Result.m_UserName = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // proceed with the current pointer
 | 
				
			||||||
 | 
					        CurrentString = LocalString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (*CurrentString == ':')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // skip ':'
 | 
				
			||||||
 | 
					            CurrentString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // read password
 | 
				
			||||||
 | 
					            LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (*LocalString && *LocalString != '@')
 | 
				
			||||||
 | 
					                LocalString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Result.m_Password = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            CurrentString = LocalString;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // skip '@'
 | 
				
			||||||
 | 
					        if (*CurrentString != '@')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return clParseURL(LUrlParserError_NoAtSign);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CurrentString++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool bHasBracket = (*CurrentString == '[');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // go ahead, read the host name
 | 
				
			||||||
 | 
					    LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (*LocalString)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (bHasBracket && *LocalString == ']')
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // end of IPv6 address
 | 
				
			||||||
 | 
					            LocalString++;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/'))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // port number is specified
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LocalString++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Result.m_Host = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentString = LocalString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // is port number specified?
 | 
				
			||||||
 | 
					    if (*CurrentString == ':')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CurrentString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // read port number
 | 
				
			||||||
 | 
					        LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (*LocalString && *LocalString != '/')
 | 
				
			||||||
 | 
					            LocalString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Result.m_Port = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CurrentString = LocalString;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // end of string
 | 
				
			||||||
 | 
					    if (!*CurrentString)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Result.m_ErrorCode = LUrlParserError_Ok;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // skip '/'
 | 
				
			||||||
 | 
					    if (*CurrentString != '/')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return clParseURL(LUrlParserError_NoSlash);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // parse the path
 | 
				
			||||||
 | 
					    LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (*LocalString && *LocalString != '#' && *LocalString != '?')
 | 
				
			||||||
 | 
					        LocalString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Result.m_Path = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentString = LocalString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // check for query
 | 
				
			||||||
 | 
					    if (*CurrentString == '?')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // skip '?'
 | 
				
			||||||
 | 
					        CurrentString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // read query
 | 
				
			||||||
 | 
					        LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (*LocalString && *LocalString != '#')
 | 
				
			||||||
 | 
					            LocalString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Result.m_Query = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CurrentString = LocalString;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // check for fragment
 | 
				
			||||||
 | 
					    if (*CurrentString == '#')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // skip '#'
 | 
				
			||||||
 | 
					        CurrentString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // read fragment
 | 
				
			||||||
 | 
					        LocalString = CurrentString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (*LocalString)
 | 
				
			||||||
 | 
					            LocalString++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Result.m_Fragment = std::string(CurrentString, LocalString - CurrentString);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Result.m_ErrorCode = LUrlParserError_Ok;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								ixwebsocket/LUrlParser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								ixwebsocket/LUrlParser.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Lightweight URL & URI parser (RFC 1738, RFC 3986)
 | 
				
			||||||
 | 
					 * https://github.com/corporateshark/LUrlParser
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The MIT License (MIT)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Sergey Kosarevsky (sk@linderdaum.com)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					 * of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					 * in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					 * copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					 * furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					 * copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					 * SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace LUrlParser
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    enum LUrlParserError
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LUrlParserError_Ok = 0,
 | 
				
			||||||
 | 
					        LUrlParserError_Uninitialized = 1,
 | 
				
			||||||
 | 
					        LUrlParserError_NoUrlCharacter = 2,
 | 
				
			||||||
 | 
					        LUrlParserError_InvalidSchemeName = 3,
 | 
				
			||||||
 | 
					        LUrlParserError_NoDoubleSlash = 4,
 | 
				
			||||||
 | 
					        LUrlParserError_NoAtSign = 5,
 | 
				
			||||||
 | 
					        LUrlParserError_UnexpectedEndOfLine = 6,
 | 
				
			||||||
 | 
					        LUrlParserError_NoSlash = 7,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class clParseURL
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        LUrlParserError m_ErrorCode;
 | 
				
			||||||
 | 
					        std::string m_Scheme;
 | 
				
			||||||
 | 
					        std::string m_Host;
 | 
				
			||||||
 | 
					        std::string m_Port;
 | 
				
			||||||
 | 
					        std::string m_Path;
 | 
				
			||||||
 | 
					        std::string m_Query;
 | 
				
			||||||
 | 
					        std::string m_Fragment;
 | 
				
			||||||
 | 
					        std::string m_UserName;
 | 
				
			||||||
 | 
					        std::string m_Password;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        clParseURL()
 | 
				
			||||||
 | 
					            : m_ErrorCode(LUrlParserError_Uninitialized)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// return 'true' if the parsing was successful
 | 
				
			||||||
 | 
					        bool IsValid() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return m_ErrorCode == LUrlParserError_Ok;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// helper to convert the port number to int, return 'true' if the port is valid (within the
 | 
				
			||||||
 | 
					        /// 0..65535 range)
 | 
				
			||||||
 | 
					        bool GetPort(int* OutPort) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// parse the URL
 | 
				
			||||||
 | 
					        static clParseURL ParseURL(const std::string& URL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        explicit clParseURL(LUrlParserError ErrorCode)
 | 
				
			||||||
 | 
					            : m_ErrorCode(ErrorCode)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace LUrlParser
 | 
				
			||||||
							
								
								
									
										135
									
								
								ixwebsocket/libwshandshake.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								ixwebsocket/libwshandshake.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2016 Alex Hultman and contributors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This software is provided 'as-is', without any express or implied
 | 
				
			||||||
 | 
					// warranty. In no event will the authors be held liable for any damages
 | 
				
			||||||
 | 
					// arising from the use of this software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Permission is granted to anyone to use this software for any purpose,
 | 
				
			||||||
 | 
					// including commercial applications, and to alter it and redistribute it
 | 
				
			||||||
 | 
					// freely, subject to the following restrictions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 1. The origin of this software must not be misrepresented; you must not
 | 
				
			||||||
 | 
					//    claim that you wrote the original software. If you use this software
 | 
				
			||||||
 | 
					//    in a product, an acknowledgement in the product documentation would be
 | 
				
			||||||
 | 
					//    appreciated but is not required.
 | 
				
			||||||
 | 
					// 2. Altered source versions must be plainly marked as such, and must not be
 | 
				
			||||||
 | 
					//    misrepresented as being the original software.
 | 
				
			||||||
 | 
					// 3. This notice may not be removed or altered from any source distribution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <cstddef>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WebSocketHandshakeKeyGen {
 | 
				
			||||||
 | 
					    template <int N, typename T>
 | 
				
			||||||
 | 
					    struct static_for {
 | 
				
			||||||
 | 
					        void operator()(uint32_t *a, uint32_t *b) {
 | 
				
			||||||
 | 
					            static_for<N - 1, T>()(a, b);
 | 
				
			||||||
 | 
					            T::template f<N - 1>(a, b);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    struct static_for<0, T> {
 | 
				
			||||||
 | 
					        void operator()(uint32_t * /*a*/, uint32_t * /*hash*/) {}
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <int state>
 | 
				
			||||||
 | 
					    struct Sha1Loop {
 | 
				
			||||||
 | 
					        static inline uint32_t rol(uint32_t value, size_t bits) {return (value << bits) | (value >> (32 - bits));}
 | 
				
			||||||
 | 
					        static inline uint32_t blk(uint32_t b[16], size_t i) {
 | 
				
			||||||
 | 
					            return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        template <int i>
 | 
				
			||||||
 | 
					        static inline void f(uint32_t *a, uint32_t *b) {
 | 
				
			||||||
 | 
					            switch (state) {
 | 
				
			||||||
 | 
					            case 1:
 | 
				
			||||||
 | 
					                a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5);
 | 
				
			||||||
 | 
					                a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 2:
 | 
				
			||||||
 | 
					                b[i] = blk(b, i);
 | 
				
			||||||
 | 
					                a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5);
 | 
				
			||||||
 | 
					                a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 3:
 | 
				
			||||||
 | 
					                b[(i + 4) % 16] = blk(b, (i + 4) % 16);
 | 
				
			||||||
 | 
					                a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5);
 | 
				
			||||||
 | 
					                a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 4:
 | 
				
			||||||
 | 
					                b[(i + 8) % 16] = blk(b, (i + 8) % 16);
 | 
				
			||||||
 | 
					                a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5);
 | 
				
			||||||
 | 
					                a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 5:
 | 
				
			||||||
 | 
					                b[(i + 12) % 16] = blk(b, (i + 12) % 16);
 | 
				
			||||||
 | 
					                a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5);
 | 
				
			||||||
 | 
					                a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 6:
 | 
				
			||||||
 | 
					                b[i] += a[4 - i];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static inline void sha1(uint32_t hash[5], uint32_t b[16]) {
 | 
				
			||||||
 | 
					        uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]};
 | 
				
			||||||
 | 
					        static_for<16, Sha1Loop<1>>()(a, b);
 | 
				
			||||||
 | 
					        static_for<4, Sha1Loop<2>>()(a, b);
 | 
				
			||||||
 | 
					        static_for<20, Sha1Loop<3>>()(a, b);
 | 
				
			||||||
 | 
					        static_for<20, Sha1Loop<4>>()(a, b);
 | 
				
			||||||
 | 
					        static_for<20, Sha1Loop<5>>()(a, b);
 | 
				
			||||||
 | 
					        static_for<5, Sha1Loop<6>>()(a, hash);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static inline void base64(unsigned char *src, char *dst) {
 | 
				
			||||||
 | 
					        const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
				
			||||||
 | 
					        for (int i = 0; i < 18; i += 3) {
 | 
				
			||||||
 | 
					            *dst++ = b64[(src[i] >> 2) & 63];
 | 
				
			||||||
 | 
					            *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)];
 | 
				
			||||||
 | 
					            *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)];
 | 
				
			||||||
 | 
					            *dst++ = b64[src[i + 2] & 63];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *dst++ = b64[(src[18] >> 2) & 63];
 | 
				
			||||||
 | 
					        *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)];
 | 
				
			||||||
 | 
					        *dst++ = b64[((src[19] & 15) << 2)];
 | 
				
			||||||
 | 
					        *dst++ = '=';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    static inline void generate(const std::string& inputStr, char output[28]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        char input[25] = {};
 | 
				
			||||||
 | 
					        strncpy(input, inputStr.c_str(), 25 - 1);
 | 
				
			||||||
 | 
					        input[25 - 1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint32_t b_output[5] = {
 | 
				
			||||||
 | 
					            0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        uint32_t b_input[16] = {
 | 
				
			||||||
 | 
					            0, 0, 0, 0, 0, 0, 0x32353845, 0x41464135, 0x2d453931, 0x342d3437, 0x44412d39,
 | 
				
			||||||
 | 
					            0x3543412d, 0x43354142, 0x30444338, 0x35423131, 0x80000000
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < 6; i++) {
 | 
				
			||||||
 | 
					            b_input[i] = (input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sha1(b_output, b_input);
 | 
				
			||||||
 | 
					        uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480};
 | 
				
			||||||
 | 
					        sha1(b_output, last_b);
 | 
				
			||||||
 | 
					        for (int i = 0; i < 5; i++) {
 | 
				
			||||||
 | 
					            uint32_t tmp = b_output[i];
 | 
				
			||||||
 | 
					            char *bytes = (char *) &b_output[i];
 | 
				
			||||||
 | 
					            bytes[3] = tmp & 0xff;
 | 
				
			||||||
 | 
					            bytes[2] = (tmp >> 8) & 0xff;
 | 
				
			||||||
 | 
					            bytes[1] = (tmp >> 16) & 0xff;
 | 
				
			||||||
 | 
					            bytes[0] = (tmp >> 24) & 0xff;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        base64((unsigned char *) b_output, output);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										16
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								makefile
									
									
									
									
									
								
							@@ -20,13 +20,13 @@ install: brew
 | 
				
			|||||||
# Release, Debug, MinSizeRel, RelWithDebInfo are the build types
 | 
					# Release, Debug, MinSizeRel, RelWithDebInfo are the build types
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
brew:
 | 
					brew:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j 4 install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Docker default target. We've add problem with OpenSSL and TLS 1.3 (on the
 | 
					# Docker default target. We've add problem with OpenSSL and TLS 1.3 (on the
 | 
				
			||||||
# server side ?) and I can't work-around it easily, so we're using mbedtls on
 | 
					# server side ?) and I can't work-around it easily, so we're using mbedtls on
 | 
				
			||||||
# Linux for the SSL backend, which works great.
 | 
					# Linux for the SSL backend, which works great.
 | 
				
			||||||
ws_mbedtls_install:
 | 
					ws_mbedtls_install:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; make -j 4 install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws:
 | 
					ws:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4)
 | 
				
			||||||
@@ -103,10 +103,6 @@ test_server:
 | 
				
			|||||||
# env TEST=Websocket_chat make test
 | 
					# env TEST=Websocket_chat make test
 | 
				
			||||||
# env TEST=heartbeat make test
 | 
					# env TEST=heartbeat make test
 | 
				
			||||||
test:
 | 
					test:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
					 | 
				
			||||||
	(cd test ; python2.7 run.py -r)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test_make:
 | 
					 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j 4)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j 4)
 | 
				
			||||||
	(cd test ; python2.7 run.py -r)
 | 
						(cd test ; python2.7 run.py -r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -120,12 +116,10 @@ test_ubsan:
 | 
				
			|||||||
	(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
 | 
						(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
 | 
				
			||||||
	(cd test ; python2.7 run.py -r)
 | 
						(cd test ; python2.7 run.py -r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_asan: build_test_asan
 | 
					test_asan:
 | 
				
			||||||
	(cd test ; python2.7 run.py -r)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
build_test_asan:
 | 
					 | 
				
			||||||
	mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableAddressSanitizer YES)
 | 
						mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableAddressSanitizer YES)
 | 
				
			||||||
	(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
 | 
						(cd build/test ; ln -sf Debug/ixwebsocket_unittest)
 | 
				
			||||||
 | 
						(cd test ; python2.7 run.py -r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_tsan_openssl:
 | 
					test_tsan_openssl:
 | 
				
			||||||
	mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 -DUSE_OPEN_SSL=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableThreadSanitizer YES)
 | 
						mkdir -p build && (cd build && cmake -GXcode -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 -DUSE_OPEN_SSL=1 .. && xcodebuild -project ixwebsocket.xcodeproj -target ixwebsocket_unittest -enableThreadSanitizer YES)
 | 
				
			||||||
@@ -148,7 +142,7 @@ test_tsan_mbedtls:
 | 
				
			|||||||
	(cd test ; python2.7 run.py -r)
 | 
						(cd test ; python2.7 run.py -r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build_test_openssl:
 | 
					build_test_openssl:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPEN_SSL=1 -DUSE_TEST=1 .. ; ninja install)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPEN_SSL=1 -DUSE_TEST=1 .. ; make -j 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_openssl: build_test_openssl
 | 
					test_openssl: build_test_openssl
 | 
				
			||||||
	(cd test ; python2.7 run.py -r)
 | 
						(cd test ; python2.7 run.py -r)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,13 @@ if (UNIX)
 | 
				
			|||||||
    IXCobraMetricsPublisherTest.cpp
 | 
					    IXCobraMetricsPublisherTest.cpp
 | 
				
			||||||
    IXCobraToSentryBotTest.cpp
 | 
					    IXCobraToSentryBotTest.cpp
 | 
				
			||||||
    IXCobraToStatsdBotTest.cpp
 | 
					    IXCobraToStatsdBotTest.cpp
 | 
				
			||||||
    IXCobraToStdoutBotTest.cpp
 | 
					  )
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Some unittest fail for dubious reason on Ubuntu Xenial with TSAN
 | 
				
			||||||
 | 
					if (MAC OR WIN32)
 | 
				
			||||||
 | 
					  list(APPEND SOURCES
 | 
				
			||||||
 | 
					    IXWebSocketMessageQTest.cpp
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -180,40 +180,44 @@ namespace
 | 
				
			|||||||
        _conn.configure(_cobraConfig);
 | 
					        _conn.configure(_cobraConfig);
 | 
				
			||||||
        _conn.connect();
 | 
					        _conn.connect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _conn.setEventCallback([this, channel](const CobraEventPtr& event) {
 | 
					        _conn.setEventCallback([this, channel](ix::CobraConnectionEventType eventType,
 | 
				
			||||||
            if (event->type == ix::CobraEventType::Open)
 | 
					                                               const std::string& errMsg,
 | 
				
			||||||
 | 
					                                               const ix::WebSocketHttpHeaders& headers,
 | 
				
			||||||
 | 
					                                               const std::string& subscriptionId,
 | 
				
			||||||
 | 
					                                               CobraConnection::MsgId msgId) {
 | 
				
			||||||
 | 
					            if (eventType == ix::CobraConnection_EventType_Open)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log("Subscriber connected: " + _user);
 | 
					                log("Subscriber connected: " + _user);
 | 
				
			||||||
                for (auto&& it : event->headers)
 | 
					                for (auto&& it : headers)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    log("Headers " + it.first + " " + it.second);
 | 
					                    log("Headers " + it.first + " " + it.second);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Authenticated)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Authenticated)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log("Subscriber authenticated: " + _user);
 | 
					                log("Subscriber authenticated: " + _user);
 | 
				
			||||||
                subscribe(channel);
 | 
					                subscribe(channel);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Error)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Error)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log(event->errMsg + _user);
 | 
					                log(errMsg + _user);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Closed)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Closed)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log("Connection closed: " + _user);
 | 
					                log("Connection closed: " + _user);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Subscribed)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Subscribed)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log("Subscription ok: " + _user + " subscription_id " + event->subscriptionId);
 | 
					                log("Subscription ok: " + _user + " subscription_id " + subscriptionId);
 | 
				
			||||||
                _connectedAndSubscribed = true;
 | 
					                _connectedAndSubscribed = true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::UnSubscribed)
 | 
					            else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log("Unsubscription ok: " + _user + " subscription_id " + event->subscriptionId);
 | 
					                log("Unsubscription ok: " + _user + " subscription_id " + subscriptionId);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Published)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Published)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TLogger() << "Subscriber: published message acked: " << event->msgId;
 | 
					                TLogger() << "Subscriber: published message acked: " << msgId;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -244,7 +248,11 @@ namespace
 | 
				
			|||||||
        ix::msleep(50);
 | 
					        ix::msleep(50);
 | 
				
			||||||
        _conn.disconnect();
 | 
					        _conn.disconnect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _conn.setEventCallback([](const CobraEventPtr& /*event*/) {});
 | 
					        _conn.setEventCallback([](ix::CobraConnectionEventType /*eventType*/,
 | 
				
			||||||
 | 
					                                  const std::string& /*errMsg*/,
 | 
				
			||||||
 | 
					                                  const ix::WebSocketHttpHeaders& /*headers*/,
 | 
				
			||||||
 | 
					                                  const std::string& /*subscriptionId*/,
 | 
				
			||||||
 | 
					                                  CobraConnection::MsgId /*msgId*/) { ; });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,24 +54,24 @@ namespace
 | 
				
			|||||||
        conn.configure(config);
 | 
					        conn.configure(config);
 | 
				
			||||||
        conn.connect();
 | 
					        conn.connect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        conn.setEventCallback([&conn, &channel](const CobraEventPtr& event) {
 | 
					        conn.setEventCallback([&conn, &channel](ix::CobraConnectionEventType eventType,
 | 
				
			||||||
            if (event->type == ix::CobraEventType::Open)
 | 
					                                                const std::string& errMsg,
 | 
				
			||||||
 | 
					                                                const ix::WebSocketHttpHeaders& headers,
 | 
				
			||||||
 | 
					                                                const std::string& subscriptionId,
 | 
				
			||||||
 | 
					                                                CobraConnection::MsgId msgId) {
 | 
				
			||||||
 | 
					            if (eventType == ix::CobraConnection_EventType_Open)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TLogger() << "Subscriber connected:";
 | 
					                TLogger() << "Subscriber connected:";
 | 
				
			||||||
                for (auto&& it : event->headers)
 | 
					                for (auto&& it : headers)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    log("Headers " + it.first + " " + it.second);
 | 
					                    log("Headers " + it.first + " " + it.second);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Closed)
 | 
					            if (eventType == ix::CobraConnection_EventType_Error)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TLogger() << "Subscriber closed:" << event->errMsg;
 | 
					                TLogger() << "Subscriber error:" << errMsg;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Error)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Authenticated)
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TLogger() << "Subscriber error:" << event->errMsg;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Authenticated)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                log("Subscriber authenticated");
 | 
					                log("Subscriber authenticated");
 | 
				
			||||||
                std::string filter;
 | 
					                std::string filter;
 | 
				
			||||||
@@ -92,29 +92,29 @@ namespace
 | 
				
			|||||||
                                   gMessageCount++;
 | 
					                                   gMessageCount++;
 | 
				
			||||||
                               });
 | 
					                               });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Subscribed)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Subscribed)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TLogger() << "Subscriber: subscribed to channel " << event->subscriptionId;
 | 
					                TLogger() << "Subscriber: subscribed to channel " << subscriptionId;
 | 
				
			||||||
                if (event->subscriptionId == channel)
 | 
					                if (subscriptionId == channel)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    gSubscriberConnectedAndSubscribed = true;
 | 
					                    gSubscriberConnectedAndSubscribed = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    TLogger() << "Subscriber: unexpected channel " << event->subscriptionId;
 | 
					                    TLogger() << "Subscriber: unexpected channel " << subscriptionId;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::UnSubscribed)
 | 
					            else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TLogger() << "Subscriber: ununexpected from channel " << event->subscriptionId;
 | 
					                TLogger() << "Subscriber: ununexpected from channel " << subscriptionId;
 | 
				
			||||||
                if (event->subscriptionId != channel)
 | 
					                if (subscriptionId != channel)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    TLogger() << "Subscriber: unexpected channel " << event->subscriptionId;
 | 
					                    TLogger() << "Subscriber: unexpected channel " << subscriptionId;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (event->type == ix::CobraEventType::Published)
 | 
					            else if (eventType == ix::CobraConnection_EventType_Published)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                TLogger() << "Subscriber: published message acked: " << event->msgId;
 | 
					                TLogger() << "Subscriber: published message acked: " << msgId;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,12 +138,12 @@ TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::thread publisherThread(runPublisher, config, channel);
 | 
					        std::thread publisherThread(runPublisher, config, channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ix::CobraBotConfig cobraBotConfig;
 | 
					        std::string filter;
 | 
				
			||||||
        cobraBotConfig.cobraConfig = config;
 | 
					        std::string position("$");
 | 
				
			||||||
        cobraBotConfig.channel = channel;
 | 
					 | 
				
			||||||
        cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
 | 
					 | 
				
			||||||
        cobraBotConfig.enableHeartbeat = false;
 | 
					 | 
				
			||||||
        bool verbose = true;
 | 
					        bool verbose = true;
 | 
				
			||||||
 | 
					        bool strict = true;
 | 
				
			||||||
 | 
					        size_t maxQueueSize = 10;
 | 
				
			||||||
 | 
					        bool enableHeartbeat = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // FIXME: try to get this working with https instead of http
 | 
					        // FIXME: try to get this working with https instead of http
 | 
				
			||||||
        //        to regress the TLS 1.3 OpenSSL bug
 | 
					        //        to regress the TLS 1.3 OpenSSL bug
 | 
				
			||||||
@@ -158,7 +158,19 @@ TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
 | 
				
			|||||||
        SentryClient sentryClient(dsn);
 | 
					        SentryClient sentryClient(dsn);
 | 
				
			||||||
        sentryClient.setTLSOptions(tlsOptionsClient);
 | 
					        sentryClient.setTLSOptions(tlsOptionsClient);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int64_t sentCount = cobra_to_sentry_bot(cobraBotConfig, sentryClient, verbose);
 | 
					        // Only run the bot for 3 seconds
 | 
				
			||||||
 | 
					        int runtime = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int sentCount = cobra_to_sentry_bot(config,
 | 
				
			||||||
 | 
					                                            channel,
 | 
				
			||||||
 | 
					                                            filter,
 | 
				
			||||||
 | 
					                                            position,
 | 
				
			||||||
 | 
					                                            sentryClient,
 | 
				
			||||||
 | 
					                                            verbose,
 | 
				
			||||||
 | 
					                                            strict,
 | 
				
			||||||
 | 
					                                            maxQueueSize,
 | 
				
			||||||
 | 
					                                            enableHeartbeat,
 | 
				
			||||||
 | 
					                                            runtime);
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
        // We want at least 2 messages to be sent
 | 
					        // We want at least 2 messages to be sent
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,11 +87,14 @@ TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::thread publisherThread(runPublisher, config, channel);
 | 
					        std::thread publisherThread(runPublisher, config, channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ix::CobraBotConfig cobraBotConfig;
 | 
					        std::string filter;
 | 
				
			||||||
        cobraBotConfig.cobraConfig = config;
 | 
					        std::string position("$");
 | 
				
			||||||
        cobraBotConfig.channel = channel;
 | 
					        bool verbose = true;
 | 
				
			||||||
        cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
 | 
					        size_t maxQueueSize = 10;
 | 
				
			||||||
        cobraBotConfig.enableHeartbeat = false;
 | 
					        bool enableHeartbeat = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Only run the bot for 3 seconds
 | 
				
			||||||
 | 
					        int runtime = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string hostname("127.0.0.1");
 | 
					        std::string hostname("127.0.0.1");
 | 
				
			||||||
        // std::string hostname("www.google.com");
 | 
					        // std::string hostname("www.google.com");
 | 
				
			||||||
@@ -110,10 +113,19 @@ TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
 | 
				
			|||||||
        std::string fields("device.game\ndevice.os_name");
 | 
					        std::string fields("device.game\ndevice.os_name");
 | 
				
			||||||
        std::string gauge;
 | 
					        std::string gauge;
 | 
				
			||||||
        std::string timer;
 | 
					        std::string timer;
 | 
				
			||||||
        bool verbose = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int64_t sentCount =
 | 
					        int sentCount = ix::cobra_to_statsd_bot(config,
 | 
				
			||||||
            ix::cobra_to_statsd_bot(cobraBotConfig, statsdClient, fields, gauge, timer, verbose);
 | 
					                                                channel,
 | 
				
			||||||
 | 
					                                                filter,
 | 
				
			||||||
 | 
					                                                position,
 | 
				
			||||||
 | 
					                                                statsdClient,
 | 
				
			||||||
 | 
					                                                fields,
 | 
				
			||||||
 | 
					                                                gauge,
 | 
				
			||||||
 | 
					                                                timer,
 | 
				
			||||||
 | 
					                                                verbose,
 | 
				
			||||||
 | 
					                                                maxQueueSize,
 | 
				
			||||||
 | 
					                                                enableHeartbeat,
 | 
				
			||||||
 | 
					                                                runtime);
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
        // We want at least 2 messages to be sent
 | 
					        // We want at least 2 messages to be sent
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,115 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 *  IXCobraToStdoutTest.cpp
 | 
					 | 
				
			||||||
 *  Author: Benjamin Sergeant
 | 
					 | 
				
			||||||
 *  Copyright (c) 2020 Machine Zone. All rights reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXTest.h"
 | 
					 | 
				
			||||||
#include "catch.hpp"
 | 
					 | 
				
			||||||
#include <chrono>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <ixbots/IXCobraToStdoutBot.h>
 | 
					 | 
				
			||||||
#include <ixcobra/IXCobraConnection.h>
 | 
					 | 
				
			||||||
#include <ixcobra/IXCobraMetricsPublisher.h>
 | 
					 | 
				
			||||||
#include <ixcrypto/IXUuid.h>
 | 
					 | 
				
			||||||
#include <ixsentry/IXSentryClient.h>
 | 
					 | 
				
			||||||
#include <ixsnake/IXRedisServer.h>
 | 
					 | 
				
			||||||
#include <ixsnake/IXSnakeServer.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXHttpServer.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXUserAgent.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace ix;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    void runPublisher(const ix::CobraConfig& config, const std::string& channel)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ix::CobraMetricsPublisher cobraMetricsPublisher;
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.configure(config, channel);
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.setSession(uuid4());
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.enable(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Json::Value msg;
 | 
					 | 
				
			||||||
        msg["fps"] = 60;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.setGenericAttributes("game", "ody");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Wait a bit
 | 
					 | 
				
			||||||
        ix::msleep(500);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // publish some messages
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #1)
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.push("sms_metric_B_id", msg); // (msg #2)
 | 
					 | 
				
			||||||
        ix::msleep(500);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #3)
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.push("sms_metric_D_id", msg); // (msg #4)
 | 
					 | 
				
			||||||
        ix::msleep(500);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.push("sms_metric_A_id", msg); // (msg #4)
 | 
					 | 
				
			||||||
        cobraMetricsPublisher.push("sms_metric_F_id", msg); // (msg #5)
 | 
					 | 
				
			||||||
        ix::msleep(500);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
} // namespace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_CASE("Cobra_to_stdout_bot", "[cobra_bots]")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    SECTION("Exchange and count sent/received messages.")
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        int port = getFreePort();
 | 
					 | 
				
			||||||
        snake::AppConfig appConfig = makeSnakeServerConfig(port, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Start a redis server
 | 
					 | 
				
			||||||
        ix::RedisServer redisServer(appConfig.redisPort);
 | 
					 | 
				
			||||||
        auto res = redisServer.listen();
 | 
					 | 
				
			||||||
        REQUIRE(res.first);
 | 
					 | 
				
			||||||
        redisServer.start();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Start a snake server
 | 
					 | 
				
			||||||
        snake::SnakeServer snakeServer(appConfig);
 | 
					 | 
				
			||||||
        snakeServer.run();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Run the bot for a small amount of time
 | 
					 | 
				
			||||||
        std::string channel = ix::generateSessionId();
 | 
					 | 
				
			||||||
        std::string appkey("FC2F10139A2BAc53BB72D9db967b024f");
 | 
					 | 
				
			||||||
        std::string role = "_sub";
 | 
					 | 
				
			||||||
        std::string secret = "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba";
 | 
					 | 
				
			||||||
        std::string endpoint = makeCobraEndpoint(port, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ix::CobraConfig config;
 | 
					 | 
				
			||||||
        config.endpoint = endpoint;
 | 
					 | 
				
			||||||
        config.appkey = appkey;
 | 
					 | 
				
			||||||
        config.rolename = role;
 | 
					 | 
				
			||||||
        config.rolesecret = secret;
 | 
					 | 
				
			||||||
        config.socketTLSOptions = makeClientTLSOptions();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::thread publisherThread(runPublisher, config, channel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ix::CobraBotConfig cobraBotConfig;
 | 
					 | 
				
			||||||
        cobraBotConfig.cobraConfig = config;
 | 
					 | 
				
			||||||
        cobraBotConfig.channel = channel;
 | 
					 | 
				
			||||||
        cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
 | 
					 | 
				
			||||||
        cobraBotConfig.enableHeartbeat = false;
 | 
					 | 
				
			||||||
        bool quiet = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // We could try to capture the output ... not sure how.
 | 
					 | 
				
			||||||
        bool fluentd = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int64_t sentCount = ix::cobra_to_stdout_bot(cobraBotConfig, fluentd, quiet);
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // We want at least 2 messages to be sent
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        REQUIRE(sentCount >= 2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Give us 1s for all messages to be received
 | 
					 | 
				
			||||||
        ix::msleep(1000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        spdlog::info("Stopping snake server...");
 | 
					 | 
				
			||||||
        snakeServer.stop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        spdlog::info("Stopping redis server...");
 | 
					 | 
				
			||||||
        redisServer.stop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        publisherThread.join();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -4,14 +4,6 @@
 | 
				
			|||||||
 *  Copyright (c) 2019 Machine Zone. All rights reserved.
 | 
					 *  Copyright (c) 2019 Machine Zone. All rights reserved.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Using inet_addr will trigger an error on uwp without this
 | 
					 | 
				
			||||||
// FIXME: use a different api
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 | 
					 | 
				
			||||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "IXGetFreePort.h"
 | 
					#include "IXGetFreePort.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ixwebsocket/IXNetSystem.h>
 | 
					#include <ixwebsocket/IXNetSystem.h>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,8 @@
 | 
				
			|||||||
#include <ixwebsocket/IXSelectInterruptFactory.h>
 | 
					#include <ixwebsocket/IXSelectInterruptFactory.h>
 | 
				
			||||||
#include <ixwebsocket/IXSetThreadName.h>
 | 
					#include <ixwebsocket/IXSetThreadName.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocket.h>
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketAppleSSL.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSocketConnect.h>
 | 
					#include <ixwebsocket/IXSocketConnect.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketFactory.h>
 | 
					#include <ixwebsocket/IXSocketFactory.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketMbedTLS.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSocketOpenSSL.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXSocketServer.h>
 | 
					#include <ixwebsocket/IXSocketServer.h>
 | 
				
			||||||
#include <ixwebsocket/IXUrlParser.h>
 | 
					#include <ixwebsocket/IXUrlParser.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
@@ -29,9 +26,9 @@
 | 
				
			|||||||
#include <ixwebsocket/IXWebSocketCloseInfo.h>
 | 
					#include <ixwebsocket/IXWebSocketCloseInfo.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketErrorInfo.h>
 | 
					#include <ixwebsocket/IXWebSocketErrorInfo.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketHandshake.h>
 | 
					#include <ixwebsocket/IXWebSocketHandshake.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketHandshakeKeyGen.h>
 | 
					 | 
				
			||||||
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
					#include <ixwebsocket/IXWebSocketHttpHeaders.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketMessage.h>
 | 
					#include <ixwebsocket/IXWebSocketMessage.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocketMessageQueue.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketMessageType.h>
 | 
					#include <ixwebsocket/IXWebSocketMessageType.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketOpenInfo.h>
 | 
					#include <ixwebsocket/IXWebSocketOpenInfo.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketPerMessageDeflate.h>
 | 
					#include <ixwebsocket/IXWebSocketPerMessageDeflate.h>
 | 
				
			||||||
@@ -40,6 +37,8 @@
 | 
				
			|||||||
#include <ixwebsocket/IXWebSocketSendInfo.h>
 | 
					#include <ixwebsocket/IXWebSocketSendInfo.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketServer.h>
 | 
					#include <ixwebsocket/IXWebSocketServer.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocketTransport.h>
 | 
					#include <ixwebsocket/IXWebSocketTransport.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/LUrlParser.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/libwshandshake.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace ix;
 | 
					using namespace ix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXTest.h"
 | 
					#include "IXTest.h"
 | 
				
			||||||
#include "catch.hpp"
 | 
					#include "catch.hpp"
 | 
				
			||||||
#include "msgpack11.hpp"
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include "msgpack11.hpp"
 | 
				
			||||||
#include <ixwebsocket/IXSocket.h>
 | 
					#include <ixwebsocket/IXSocket.h>
 | 
				
			||||||
#include <ixwebsocket/IXSocketFactory.h>
 | 
					#include <ixwebsocket/IXSocketFactory.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
@@ -130,8 +130,7 @@ namespace
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (msg->type == ix::WebSocketMessageType::Error)
 | 
					            else if (msg->type == ix::WebSocketMessageType::Error)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ss << "websocket_broadcast_client: " << _user << " Error ! "
 | 
					                ss << "websocket_broadcast_client: " << _user << " Error ! " << msg->errorInfo.reason;
 | 
				
			||||||
                   << msg->errorInfo.reason;
 | 
					 | 
				
			||||||
                log(ss.str());
 | 
					                log(ss.str());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (msg->type == ix::WebSocketMessageType::Ping)
 | 
					            else if (msg->type == ix::WebSocketMessageType::Ping)
 | 
				
			||||||
@@ -235,7 +234,7 @@ namespace
 | 
				
			|||||||
        server.start();
 | 
					        server.start();
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace
 | 
					} // namespace ix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
 | 
					TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -248,7 +247,7 @@ TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::string session = ix::generateSessionId();
 | 
					        std::string session = ix::generateSessionId();
 | 
				
			||||||
        std::vector<std::shared_ptr<WebSocketChat>> chatClients;
 | 
					        std::vector<std::shared_ptr<WebSocketChat>> chatClients;
 | 
				
			||||||
        for (int i = 0; i < 10; ++i)
 | 
					        for (int i = 0 ; i < 10; ++i)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::string user("user_" + std::to_string(i));
 | 
					            std::string user("user_" + std::to_string(i));
 | 
				
			||||||
            chatClients.push_back(std::make_shared<WebSocketChat>(user, session, port));
 | 
					            chatClients.push_back(std::make_shared<WebSocketChat>(user, session, port));
 | 
				
			||||||
@@ -260,7 +259,7 @@ TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
 | 
				
			|||||||
        while (true)
 | 
					        while (true)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            bool allReady = true;
 | 
					            bool allReady = true;
 | 
				
			||||||
            for (size_t i = 0; i < chatClients.size(); ++i)
 | 
					            for (size_t i = 0 ; i < chatClients.size(); ++i)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                allReady &= chatClients[i]->isReady();
 | 
					                allReady &= chatClients[i]->isReady();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -270,7 +269,7 @@ TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        for (int j = 0; j < 1000; j++)
 | 
					        for (int j = 0; j < 1000; j++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            for (size_t i = 0; i < chatClients.size(); ++i)
 | 
					            for (size_t i = 0 ; i < chatClients.size(); ++i)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                chatClients[i]->sendMessage("hello world");
 | 
					                chatClients[i]->sendMessage("hello world");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -292,7 +291,7 @@ TEST_CASE("Websocket_broadcast_server", "[websocket_server]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Stop all clients
 | 
					        // Stop all clients
 | 
				
			||||||
        size_t messageCount = chatClients.size() * 50;
 | 
					        size_t messageCount = chatClients.size() * 50;
 | 
				
			||||||
        for (size_t i = 0; i < chatClients.size(); ++i)
 | 
					        for (size_t i = 0 ; i < chatClients.size(); ++i)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            REQUIRE(chatClients[i]->getReceivedMessagesCount() >= messageCount);
 | 
					            REQUIRE(chatClients[i]->getReceivedMessagesCount() >= messageCount);
 | 
				
			||||||
            chatClients[i]->stop();
 | 
					            chatClients[i]->stop();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										178
									
								
								test/IXWebSocketMessageQTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								test/IXWebSocketMessageQTest.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  IXWebSocketMessageQTest.cpp
 | 
				
			||||||
 | 
					 *  Author: Korchynskyi Dmytro
 | 
				
			||||||
 | 
					 *  Copyright (c) 2019 Machine Zone. All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IXTest.h"
 | 
				
			||||||
 | 
					#include "catch.hpp"
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocketMessageQueue.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXWebSocketServer.h>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace ix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool startServer(ix::WebSocketServer& server)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
 | 
				
			||||||
 | 
					                                                 std::shared_ptr<ConnectionState> connectionState) {
 | 
				
			||||||
 | 
					            webSocket->setOnMessageCallback(
 | 
				
			||||||
 | 
					                [connectionState, &server](const WebSocketMessagePtr& msg) {
 | 
				
			||||||
 | 
					                    if (msg->type == ix::WebSocketMessageType::Open)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        TLogger() << "New connection";
 | 
				
			||||||
 | 
					                        connectionState->computeId();
 | 
				
			||||||
 | 
					                        TLogger() << "id: " << connectionState->getId();
 | 
				
			||||||
 | 
					                        TLogger() << "Uri: " << msg->openInfo.uri;
 | 
				
			||||||
 | 
					                        TLogger() << "Headers:";
 | 
				
			||||||
 | 
					                        for (auto&& it : msg->openInfo.headers)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            TLogger() << it.first << ": " << it.second;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (msg->type == ix::WebSocketMessageType::Close)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        TLogger() << "Closed connection";
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        TLogger() << "Message received: " << msg->str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        for (auto&& client : server.getClients())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            client->send(msg->str);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto res = server.listen();
 | 
				
			||||||
 | 
					        if (!res.first)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TLogger() << res.second;
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        server.start();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class MsgQTestClient
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        MsgQTestClient()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            msgQ.bindWebsocket(&ws);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            msgQ.setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
 | 
				
			||||||
 | 
					                REQUIRE(mainThreadId == std::this_thread::get_id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                std::stringstream ss;
 | 
				
			||||||
 | 
					                if (msg->type == WebSocketMessageType::Open)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    log("client connected");
 | 
				
			||||||
 | 
					                    sendNextMessage();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (msg->type == WebSocketMessageType::Close)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    log("client disconnected");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (msg->type == WebSocketMessageType::Error)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "Error ! " << msg->errorInfo.reason;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                    testDone = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (msg->type == WebSocketMessageType::Pong)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "Received pong message " << msg->str;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (msg->type == WebSocketMessageType::Ping)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "Received ping message " << msg->str;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (msg->type == WebSocketMessageType::Message)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    REQUIRE(msg->str.compare("Hey dude!") == 0);
 | 
				
			||||||
 | 
					                    ++receivedCount;
 | 
				
			||||||
 | 
					                    ss << "Received message " << msg->str;
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                    sendNextMessage();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ss << "Invalid WebSocketMessageType";
 | 
				
			||||||
 | 
					                    log(ss.str());
 | 
				
			||||||
 | 
					                    testDone = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void sendNextMessage()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (receivedCount >= 3)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                testDone = true;
 | 
				
			||||||
 | 
					                succeeded = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto info = ws.sendText("Hey dude!");
 | 
				
			||||||
 | 
					                if (info.success)
 | 
				
			||||||
 | 
					                    log("sent message");
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    log("send failed");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void run(const std::string& url)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            mainThreadId = std::this_thread::get_id();
 | 
				
			||||||
 | 
					            testDone = false;
 | 
				
			||||||
 | 
					            receivedCount = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ws.setUrl(url);
 | 
				
			||||||
 | 
					            ws.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (!testDone)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                msgQ.poll();
 | 
				
			||||||
 | 
					                msleep(50);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool isSucceeded() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return succeeded;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        WebSocket ws;
 | 
				
			||||||
 | 
					        WebSocketMessageQueue msgQ;
 | 
				
			||||||
 | 
					        bool testDone = false;
 | 
				
			||||||
 | 
					        uint32_t receivedCount = 0;
 | 
				
			||||||
 | 
					        std::thread::id mainThreadId;
 | 
				
			||||||
 | 
					        bool succeeded = false;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Websocket_message_queue", "[websocket_message_q]")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    SECTION("Send several messages")
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int port = getFreePort();
 | 
				
			||||||
 | 
					        WebSocketServer server(port);
 | 
				
			||||||
 | 
					        REQUIRE(startServer(server));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MsgQTestClient testClient;
 | 
				
			||||||
 | 
					        testClient.run("ws://127.0.0.1:" + std::to_string(port));
 | 
				
			||||||
 | 
					        REQUIRE(testClient.isSucceeded());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        server.stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -93,11 +93,10 @@ TEST_CASE("subprotocol", "[websocket_subprotocol]")
 | 
				
			|||||||
        webSocket.setUrl(url);
 | 
					        webSocket.setUrl(url);
 | 
				
			||||||
        webSocket.start();
 | 
					        webSocket.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Give us 3 seconds to connect
 | 
					 | 
				
			||||||
        int attempts = 0;
 | 
					        int attempts = 0;
 | 
				
			||||||
        while (!connected)
 | 
					        while (!connected)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            REQUIRE(attempts++ < 300);
 | 
					            REQUIRE(attempts++ < 10);
 | 
				
			||||||
            ix::msleep(10);
 | 
					            ix::msleep(10);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,41 +14,8 @@ int main(int argc, char* argv[])
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    ix::initNetSystem();
 | 
					    ix::initNetSystem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ix::CoreLogger::LogFunc logFunc = [](const char* msg, ix::LogLevel level) {
 | 
					    ix::IXCoreLogger::LogFunc logFunc = [](const char* msg) { spdlog::info(msg); };
 | 
				
			||||||
        switch (level)
 | 
					    ix::IXCoreLogger::setLogFunction(logFunc);
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case ix::LogLevel::Debug:
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                spdlog::debug(msg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            case ix::LogLevel::Info:
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                spdlog::info(msg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            case ix::LogLevel::Warning:
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                spdlog::warn(msg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            case ix::LogLevel::Error:
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                spdlog::error(msg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            case ix::LogLevel::Critical:
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                spdlog::critical(msg);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    ix::CoreLogger::setLogFunction(logFunc);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int result = Catch::Session().run(argc, argv);
 | 
					    int result = Catch::Session().run(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								third_party/.clang-format
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								third_party/.clang-format
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,4 @@
 | 
				
			|||||||
DisableFormat: true
 | 
					{
 | 
				
			||||||
SortIncludes: false
 | 
					    "DisableFormat": true,
 | 
				
			||||||
 | 
					    "SortIncludes": false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user