Compare commits
	
		
			71 Commits
		
	
	
		
			v11.0.8
			...
			feature/pr
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0c5a4af722 | ||
| 
						 | 
					3baf59a031 | ||
| 
						 | 
					b5804c2082 | ||
| 
						 | 
					30bcddb99f | ||
| 
						 | 
					47fd04e210 | ||
| 
						 | 
					4f5b0c4f07 | ||
| 
						 | 
					c2d497abc5 | ||
| 
						 | 
					bbe2ae6dd3 | ||
| 
						 | 
					26897b2425 | ||
| 
						 | 
					e3c98a03cc | ||
| 
						 | 
					97fedf9482 | ||
| 
						 | 
					ae187c0e98 | ||
| 
						 | 
					0f21a20fe3 | ||
| 
						 | 
					54db6ec8bb | ||
| 
						 | 
					0e0a748037 | ||
| 
						 | 
					3b19b0eeca | ||
| 
						 | 
					dbfe3104e8 | ||
| 
						 | 
					68fd8c20d6 | ||
| 
						 | 
					d932af8568 | ||
| 
						 | 
					3add6d4c2e | ||
| 
						 | 
					0d7fb05567 | ||
| 
						 | 
					bf1747ef18 | ||
| 
						 | 
					5c9c05caff | ||
| 
						 | 
					2573ca151b | ||
| 
						 | 
					c5b5fa82be | ||
| 
						 | 
					80dff08304 | ||
| 
						 | 
					24c2eae3d7 | ||
| 
						 | 
					449c5fa138 | ||
| 
						 | 
					b6234ff908 | ||
| 
						 | 
					d26664fccc | ||
| 
						 | 
					def0243d6d | ||
| 
						 | 
					1410797d6f | ||
| 
						 | 
					2670187fe0 | ||
| 
						 | 
					95359461d7 | ||
| 
						 | 
					4d7b149649 | ||
| 
						 | 
					b29a37ce76 | ||
| 
						 | 
					9a4dfb40da | ||
| 
						 | 
					c4c344518d | ||
| 
						 | 
					d706a4a73e | ||
| 
						 | 
					88970604e3 | ||
| 
						 | 
					7fee54464e | ||
| 
						 | 
					1c7634d075 | ||
| 
						 | 
					99f9556aa9 | ||
| 
						 | 
					39b2a3d6df | ||
| 
						 | 
					056b02a494 | ||
| 
						 | 
					48166a9a72 | ||
| 
						 | 
					b36a2d1faa | ||
| 
						 | 
					968cc5c1c4 | ||
| 
						 | 
					0813eb1788 | ||
| 
						 | 
					cadb8336f2 | ||
| 
						 | 
					7fd782f72f | ||
| 
						 | 
					85bcdaaec3 | ||
| 
						 | 
					461641f3d0 | ||
| 
						 | 
					2d65c27d11 | ||
| 
						 | 
					6a7785d9d9 | ||
| 
						 | 
					78a670e0c8 | ||
| 
						 | 
					e63ac69ec6 | ||
| 
						 | 
					afa15d6dcf | ||
| 
						 | 
					432a202c07 | ||
| 
						 | 
					d609370a85 | ||
| 
						 | 
					bbe3a766f4 | ||
| 
						 | 
					09d3520b66 | ||
| 
						 | 
					f090c7659b | ||
| 
						 | 
					7c195219cd | ||
| 
						 | 
					d739662a7c | ||
| 
						 | 
					e7f7e470e2 | ||
| 
						 | 
					d239738ec6 | ||
| 
						 | 
					c61975bf75 | ||
| 
						 | 
					39cc0ed32f | ||
| 
						 | 
					22c3a7264e | ||
| 
						 | 
					ee5a2eb46e | 
							
								
								
									
										2
									
								
								.github/workflows/mkdocs.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/mkdocs.yml
									
									
									
									
										vendored
									
									
								
							@@ -21,5 +21,7 @@ jobs:
 | 
				
			|||||||
        pip install pygments
 | 
					        pip install pygments
 | 
				
			||||||
    - name: Build doc
 | 
					    - name: Build doc
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
 | 
					        git clean -dfx .
 | 
				
			||||||
 | 
					        git fetch
 | 
				
			||||||
        git pull
 | 
					        git pull
 | 
				
			||||||
        mkdocs gh-deploy
 | 
					        mkdocs gh-deploy
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/unittest_linux.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/unittest_linux.yml
									
									
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  linux:
 | 
					  linux:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/unittest_linux_asan.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/unittest_linux_asan.yml
									
									
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  linux:
 | 
					  linux:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  mac_tsan_mbedtls:
 | 
					  mac_tsan_mbedtls:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  mac_tsan_openssl:
 | 
					  mac_tsan_openssl:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  mac_tsan_sectransport:
 | 
					  mac_tsan_sectransport:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/workflows/unittest_uwp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/unittest_uwp.yml
									
									
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  uwp:
 | 
					  uwp:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.github/workflows/unittest_windows.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/unittest_windows.yml
									
									
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ on:
 | 
				
			|||||||
  push:
 | 
					  push:
 | 
				
			||||||
    paths-ignore:
 | 
					    paths-ignore:
 | 
				
			||||||
    - 'docs/**'
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  windows:
 | 
					  windows:
 | 
				
			||||||
@@ -14,7 +15,7 @@ jobs:
 | 
				
			|||||||
    - run: |
 | 
					    - run: |
 | 
				
			||||||
        mkdir build
 | 
					        mkdir build
 | 
				
			||||||
        cd build
 | 
					        cd build
 | 
				
			||||||
        cmake -GNinja -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 -DUSE_ZLIB=0 ..
 | 
					        cmake -GNinja -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 -DUSE_ZLIB=OFF -DBUILD_SHARED_LIBS=OFF ..
 | 
				
			||||||
    - run: |
 | 
					    - run: |
 | 
				
			||||||
        cd build
 | 
					        cd build
 | 
				
			||||||
        ninja
 | 
					        ninja
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								.github/workflows/unittest_windows_gcc.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								.github/workflows/unittest_windows_gcc.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					name: windows_gcc
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    paths-ignore:
 | 
				
			||||||
 | 
					    - 'docs/**'
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  windows:
 | 
				
			||||||
 | 
					    runs-on: windows-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v1
 | 
				
			||||||
 | 
					    - uses: seanmiddleditch/gha-setup-ninja@master
 | 
				
			||||||
 | 
					    - uses: egor-tensin/setup-mingw@v2
 | 
				
			||||||
 | 
					    - run: |
 | 
				
			||||||
 | 
					        mkdir build
 | 
				
			||||||
 | 
					        cd build
 | 
				
			||||||
 | 
					        cmake -GNinja -DCMAKE_CXX_COMPILER=c++ -DCMAKE_C_COMPILER=cc -DUSE_WS=1 -DUSE_TEST=1 -DUSE_ZLIB=0 -DCMAKE_UNITY_BUILD=ON ..
 | 
				
			||||||
 | 
					    - run: |
 | 
				
			||||||
 | 
					        cd build
 | 
				
			||||||
 | 
					        ninja
 | 
				
			||||||
 | 
					    - run: |
 | 
				
			||||||
 | 
					        cd build
 | 
				
			||||||
 | 
					        ctest -V
 | 
				
			||||||
 | 
					        # ninja test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#- run: ../build/test/ixwebsocket_unittest.exe
 | 
				
			||||||
 | 
					# working-directory: test
 | 
				
			||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -7,3 +7,4 @@ ws/.certs/
 | 
				
			|||||||
ws/.srl
 | 
					ws/.srl
 | 
				
			||||||
ixhttpd
 | 
					ixhttpd
 | 
				
			||||||
makefile
 | 
					makefile
 | 
				
			||||||
 | 
					a.out
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@ set (CMAKE_CXX_STANDARD 11)
 | 
				
			|||||||
set (CXX_STANDARD_REQUIRED ON)
 | 
					set (CXX_STANDARD_REQUIRED ON)
 | 
				
			||||||
set (CMAKE_CXX_EXTENSIONS OFF)
 | 
					set (CMAKE_CXX_EXTENSIONS OFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option (BUILD_DEMO OFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 | 
					if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 | 
				
			||||||
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
					  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
@@ -86,6 +88,7 @@ set( IXWEBSOCKET_HEADERS
 | 
				
			|||||||
    ixwebsocket/IXSocketTLSOptions.h
 | 
					    ixwebsocket/IXSocketTLSOptions.h
 | 
				
			||||||
    ixwebsocket/IXStrCaseCompare.h
 | 
					    ixwebsocket/IXStrCaseCompare.h
 | 
				
			||||||
    ixwebsocket/IXUdpSocket.h
 | 
					    ixwebsocket/IXUdpSocket.h
 | 
				
			||||||
 | 
					    ixwebsocket/IXUniquePtr.h
 | 
				
			||||||
    ixwebsocket/IXUrlParser.h
 | 
					    ixwebsocket/IXUrlParser.h
 | 
				
			||||||
    ixwebsocket/IXUuid.h
 | 
					    ixwebsocket/IXUuid.h
 | 
				
			||||||
    ixwebsocket/IXUtf8Validator.h
 | 
					    ixwebsocket/IXUtf8Validator.h
 | 
				
			||||||
@@ -111,6 +114,7 @@ set( IXWEBSOCKET_HEADERS
 | 
				
			|||||||
    ixwebsocket/IXWebSocketVersion.h
 | 
					    ixwebsocket/IXWebSocketVersion.h
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" OFF)
 | 
				
			||||||
option(USE_TLS "Enable TLS support" FALSE)
 | 
					option(USE_TLS "Enable TLS support" FALSE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (USE_TLS)
 | 
					if (USE_TLS)
 | 
				
			||||||
@@ -144,7 +148,7 @@ if (USE_TLS)
 | 
				
			|||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_library( ixwebsocket STATIC
 | 
					add_library( ixwebsocket
 | 
				
			||||||
    ${IXWEBSOCKET_SOURCES}
 | 
					    ${IXWEBSOCKET_SOURCES}
 | 
				
			||||||
    ${IXWEBSOCKET_HEADERS}
 | 
					    ${IXWEBSOCKET_HEADERS}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -191,7 +195,7 @@ if (USE_TLS)
 | 
				
			|||||||
    target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES})
 | 
					    target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES})
 | 
				
			||||||
  elseif (USE_SECURE_TRANSPORT)
 | 
					  elseif (USE_SECURE_TRANSPORT)
 | 
				
			||||||
    message(STATUS "TLS configured to use secure transport")
 | 
					    message(STATUS "TLS configured to use secure transport")
 | 
				
			||||||
    target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
 | 
					    target_link_libraries(ixwebsocket "-framework Foundation" "-framework Security")
 | 
				
			||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -273,3 +277,8 @@ if (USE_WS OR USE_TEST)
 | 
				
			|||||||
    add_subdirectory(test)
 | 
					    add_subdirectory(test)
 | 
				
			||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (BUILD_DEMO) 
 | 
				
			||||||
 | 
					  add_executable(demo main.cpp)
 | 
				
			||||||
 | 
					  target_link_libraries(demo ixwebsocket) 
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								README.md
									
									
									
									
									
								
							@@ -15,13 +15,16 @@ A bad security bug affecting users compiling with SSL enabled and OpenSSL as the
 | 
				
			|||||||
 *  Super simple standalone example. See ws folder, unittest and doc/usage.md for more.
 | 
					 *  Super simple standalone example. See ws folder, unittest and doc/usage.md for more.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  On macOS
 | 
					 *  On macOS
 | 
				
			||||||
 *  $ mkdir -p build ; cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install
 | 
					 *  $ mkdir -p build ; (cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install)
 | 
				
			||||||
 *  $ clang++ --std=c++14 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation
 | 
					 *  $ clang++ --std=c++11 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation
 | 
				
			||||||
 *  $ ./a.out
 | 
					 *  $ ./a.out
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Or use cmake -DBUILD_DEMO=ON option for other platforms
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ixwebsocket/IXNetSystem.h>
 | 
					#include <ixwebsocket/IXNetSystem.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXUserAgent.h>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main()
 | 
					int main()
 | 
				
			||||||
@@ -32,6 +35,8 @@ int main()
 | 
				
			|||||||
    // Our websocket object
 | 
					    // Our websocket object
 | 
				
			||||||
    ix::WebSocket webSocket;
 | 
					    ix::WebSocket webSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Connect to a server with encryption
 | 
				
			||||||
 | 
					    // See https://machinezone.github.io/IXWebSocket/usage/#tls-support-and-configuration
 | 
				
			||||||
    std::string url("wss://echo.websocket.org");
 | 
					    std::string url("wss://echo.websocket.org");
 | 
				
			||||||
    webSocket.setUrl(url);
 | 
					    webSocket.setUrl(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,10 +49,18 @@ int main()
 | 
				
			|||||||
            if (msg->type == ix::WebSocketMessageType::Message)
 | 
					            if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::cout << "received message: " << msg->str << std::endl;
 | 
					                std::cout << "received message: " << msg->str << std::endl;
 | 
				
			||||||
 | 
					                std::cout << "> " << std::flush;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (msg->type == ix::WebSocketMessageType::Open)
 | 
					            else if (msg->type == ix::WebSocketMessageType::Open)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::cout << "Connection established" << std::endl;
 | 
					                std::cout << "Connection established" << std::endl;
 | 
				
			||||||
 | 
					                std::cout << "> " << std::flush;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (msg->type == ix::WebSocketMessageType::Error)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // Maybe SSL is not configured properly
 | 
				
			||||||
 | 
					                std::cout << "Connection error: " << msg->errorInfo.reason << std::endl;
 | 
				
			||||||
 | 
					                std::cout << "> " << std::flush;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -58,13 +71,16 @@ int main()
 | 
				
			|||||||
    // Send a message to the server (default to TEXT mode)
 | 
					    // Send a message to the server (default to TEXT mode)
 | 
				
			||||||
    webSocket.send("hello world");
 | 
					    webSocket.send("hello world");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (true)
 | 
					    // Display a prompt
 | 
				
			||||||
    {
 | 
					    std::cout << "> " << std::flush;
 | 
				
			||||||
        std::string text;
 | 
					 | 
				
			||||||
        std::cout << "> " << std::flush;
 | 
					 | 
				
			||||||
        std::getline(std::cin, text);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string text;
 | 
				
			||||||
 | 
					    // Read text from the console and send messages in text mode.
 | 
				
			||||||
 | 
					    // Exit with Ctrl-D on Unix or Ctrl-Z on Windows.
 | 
				
			||||||
 | 
					    while (std::getline(std::cin, text))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        webSocket.send(text);
 | 
					        webSocket.send(text);
 | 
				
			||||||
 | 
					        std::cout << "> " << std::flush;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@@ -77,6 +93,8 @@ IXWebSocket is actively being developed, check out the [changelog](https://machi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/autobahn/reports/clients/index.html). Some tests are still failing in the server code.
 | 
					IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/autobahn/reports/clients/index.html). Some tests are still failing in the server code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Starting with the 11.0.8 release, IXWebSocket should be fully C++11 compatible.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Users
 | 
					## Users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.
 | 
				
			||||||
@@ -87,6 +105,7 @@ If your company or project is using this library, feel free to open an issue or
 | 
				
			|||||||
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
 | 
					- [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
 | 
					- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
 | 
				
			||||||
- [discord.cpp](https://github.com/luccanunes/discord.cpp), a discord library for making bots
 | 
					- [discord.cpp](https://github.com/luccanunes/discord.cpp), a discord library for making bots
 | 
				
			||||||
 | 
					- [Teleport](http://teleportconnect.com/), Teleport is your own personal remote robot avatar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Alternative libraries
 | 
					## Alternative libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,6 +115,7 @@ There are plenty of great websocket libraries out there, which might work for yo
 | 
				
			|||||||
* [beast](https://github.com/boostorg/beast) - C++
 | 
					* [beast](https://github.com/boostorg/beast) - C++
 | 
				
			||||||
* [libwebsockets](https://libwebsockets.org/) - C
 | 
					* [libwebsockets](https://libwebsockets.org/) - C
 | 
				
			||||||
* [µWebSockets](https://github.com/uNetworking/uWebSockets) - C
 | 
					* [µWebSockets](https://github.com/uNetworking/uWebSockets) - C
 | 
				
			||||||
 | 
					* [wslay](https://github.com/tatsuhiro-t/wslay) - C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[uvweb](https://github.com/bsergean/uvweb) is a library written by the IXWebSocket author which is built on top of [uvw](https://github.com/skypjack/uvw), which is a C++ wrapper for [libuv](https://libuv.org/). It has more dependencies and does not support SSL at this point, but it can be used to open multiple connections within a single OS thread thanks to libuv.
 | 
					[uvweb](https://github.com/bsergean/uvweb) is a library written by the IXWebSocket author which is built on top of [uvw](https://github.com/skypjack/uvw), which is a C++ wrapper for [libuv](https://libuv.org/). It has more dependencies and does not support SSL at this point, but it can be used to open multiple connections within a single OS thread thanks to libuv.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,6 +132,7 @@ To check the performance of a websocket library, you can look at the [autoroute]
 | 
				
			|||||||
| Windows           | Disabled          | None              | [![Build2][5]][0] |
 | 
					| Windows           | Disabled          | None              | [![Build2][5]][0] |
 | 
				
			||||||
| UWP               | Disabled          | None              | [![Build2][6]][0] |
 | 
					| UWP               | Disabled          | None              | [![Build2][6]][0] |
 | 
				
			||||||
| Linux             | OpenSSL           | Address Sanitizer | [![Build2][7]][0] |
 | 
					| Linux             | OpenSSL           | Address Sanitizer | [![Build2][7]][0] |
 | 
				
			||||||
 | 
					| Mingw             | Disabled          | None              | [![Build2][8]][0] |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* ASAN fails on Linux because of a known problem, we need a 
 | 
					* ASAN fails on Linux because of a known problem, we need a 
 | 
				
			||||||
* Some tests are disabled on Windows/UWP because of a pathing problem
 | 
					* Some tests are disabled on Windows/UWP because of a pathing problem
 | 
				
			||||||
@@ -125,4 +146,5 @@ To check the performance of a websocket library, you can look at the [autoroute]
 | 
				
			|||||||
[5]: https://github.com/machinezone/IXWebSocket/workflows/windows/badge.svg
 | 
					[5]: https://github.com/machinezone/IXWebSocket/workflows/windows/badge.svg
 | 
				
			||||||
[6]: https://github.com/machinezone/IXWebSocket/workflows/uwp/badge.svg
 | 
					[6]: https://github.com/machinezone/IXWebSocket/workflows/uwp/badge.svg
 | 
				
			||||||
[7]: https://github.com/machinezone/IXWebSocket/workflows/linux_asan/badge.svg
 | 
					[7]: https://github.com/machinezone/IXWebSocket/workflows/linux_asan/badge.svg
 | 
				
			||||||
 | 
					[8]: https://github.com/machinezone/IXWebSocket/workflows/unittest_windows_gcc/badge.svg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,74 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
All changes to this project will be documented in this file.
 | 
					All changes to this project will be documented in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.10] - 2021-07-27
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ws) bump CLI command line parsing library from 1.8 to 2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.9] - 2021-06-08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ws) ws connect has a -g option to gzip decompress messages for API such as the websocket Huobi Global.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.8] - 2021-06-03
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(websocket client + server) WebSocketMessage class tweak to fix unsafe patterns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.7] - 2021-05-27
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(websocket server) Handle and accept firefox browser special upgrade value (keep-alive, Upgrade)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.6] - 2021-05-18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(Windows) move EINVAL (re)definition from IXSocket.h to IXNetSystem.h (fix #289)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.5] - 2021-04-04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(http client) DEL is not an HTTP method name, but DELETE is
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.4] - 2021-03-25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(cmake) install IXUniquePtr.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.3] - 2021-03-24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ssl + windows) missing include for CertOpenStore function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.2] - 2021-03-23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) version bump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.1] - 2021-03-23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) version bump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.2.0] - 2021-03-23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) correct mingw support (gcc on windows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.1.4] - 2021-03-23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) add getMinWaitBetweenReconnectionRetries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.1.3] - 2021-03-23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) New option to set the min wait between reconnection attempts. Still default to 1ms. (setMinWaitBetweenReconnectionRetries).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.1.2] - 2021-03-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ws) initialize maxWaitBetweenReconnectionRetries to a non zero value ; a zero value was causing spurious reconnections attempts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.1.1] - 2021-03-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(cmake) Library can be built as a static or a dynamic library, controlled with BUILD_SHARED_LIBS. Default to static library
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.1.0] - 2021-03-16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) Use LEAN_AND_MEAN Windows define to help with undefined link error when building a DLL. Support websocket server disablePerMessageDeflate option correctly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [11.0.9] - 2021-03-07
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ixwebsocket) Expose setHandshakeTimeout method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [11.0.8] - 2020-12-25
 | 
					## [11.0.8] - 2020-12-25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(ws) trim ws dependencies no more ixcrypto and ixcore deps
 | 
					(ws) trim ws dependencies no more ixcrypto and ixcore deps
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,13 +17,13 @@ There is a unittest which can be executed by typing `make test`.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Options for building:
 | 
					Options for building:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `-DBUILD_SHARED_LIBS=ON` will build the unittest as a shared libary instead of a static library, which is the default
 | 
				
			||||||
* `-DUSE_ZLIB=1` will enable zlib support, required for http client + server + websocket per message deflate extension
 | 
					* `-DUSE_ZLIB=1` will enable zlib support, required for http client + server + websocket per message deflate extension
 | 
				
			||||||
* `-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_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
 | 
					* `-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
 | 
					* `-DUSE_TEST=1` will build the unittest
 | 
				
			||||||
* `-DUSE_PYTHON=1` will use Python3 for cobra bots, require Python3 to be installed.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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/unittest_windows.yml) 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 (not maintained much though) or rather the [github actions](https://github.com/machinezone/IXWebSocket/blob/master/.github/workflows/unittest_windows.yml) which have instructions for building dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -256,11 +256,24 @@ Wait time(ms): 6400
 | 
				
			|||||||
Wait time(ms): 10000
 | 
					Wait time(ms): 10000
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The waiting time is capped by default at 10s between 2 attempts, but that value can be changed and queried.
 | 
					The waiting time is capped by default at 10s between 2 attempts, but that value
 | 
				
			||||||
 | 
					can be changed and queried. The minimum waiting time can also be set.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```cpp
 | 
				
			||||||
webSocket.setMaxWaitBetweenReconnectionRetries(5 * 1000); // 5000ms = 5s
 | 
					webSocket.setMaxWaitBetweenReconnectionRetries(5 * 1000); // 5000ms = 5s
 | 
				
			||||||
uint32_t m = webSocket.getMaxWaitBetweenReconnectionRetries();
 | 
					uint32_t m = webSocket.getMaxWaitBetweenReconnectionRetries();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					webSocket.setMinWaitBetweenReconnectionRetries(1000); // 1000ms = 1s
 | 
				
			||||||
 | 
					uint32_t m = webSocket.getMinWaitBetweenReconnectionRetries();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Handshake timeout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can control how long to wait until timing out while waiting for the websocket handshake to be performed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					int handshakeTimeoutSecs = 1;
 | 
				
			||||||
 | 
					setHandshakeTimeout(handshakeTimeoutSecs);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## WebSocket server API
 | 
					## WebSocket server API
 | 
				
			||||||
@@ -334,6 +347,10 @@ if (!res.first)
 | 
				
			|||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Per message deflate connection is enabled by default. It can be disabled
 | 
				
			||||||
 | 
					// which might be helpful when running on low power devices such as a Rasbery Pi
 | 
				
			||||||
 | 
					server.disablePerMessageDeflate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Run the server in the background. Server can be stoped by calling server.stop()
 | 
					// Run the server in the background. Server can be stoped by calling server.stop()
 | 
				
			||||||
server.start();
 | 
					server.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -357,13 +374,10 @@ The webSocket reference is guaranteed to be always valid ; by design the callbac
 | 
				
			|||||||
// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
					// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
				
			||||||
ix::WebSocketServer server(port);
 | 
					ix::WebSocketServer server(port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
server.setOnClientMessageCallback(std::shared_ptr<ConnectionState> connectionState,
 | 
					server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) {
 | 
				
			||||||
                                  WebSocket& webSocket,
 | 
					 | 
				
			||||||
                                  const WebSocketMessagePtr& msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    // The ConnectionState object contains information about the connection,
 | 
					    // The ConnectionState object contains information about the connection,
 | 
				
			||||||
    // at this point only the client ip address and the port.
 | 
					    // at this point only the client ip address and the port.
 | 
				
			||||||
    std::cout << "Remote ip: " << connectionState->getRemoteIp();
 | 
					    std::cout << "Remote ip: " << connectionState->getRemoteIp() << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (msg->type == ix::WebSocketMessageType::Open)
 | 
					    if (msg->type == ix::WebSocketMessageType::Open)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -381,7 +395,7 @@ server.setOnClientMessageCallback(std::shared_ptr<ConnectionState> connectionSta
 | 
				
			|||||||
        std::cout << "Headers:" << std::endl;
 | 
					        std::cout << "Headers:" << std::endl;
 | 
				
			||||||
        for (auto it : msg->openInfo.headers)
 | 
					        for (auto it : msg->openInfo.headers)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::cout << it.first << ": " << it.second << std::endl;
 | 
					            std::cout << "\t" << it.first << ": " << it.second << std::endl;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (msg->type == ix::WebSocketMessageType::Message)
 | 
					    else if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
@@ -390,9 +404,11 @@ server.setOnClientMessageCallback(std::shared_ptr<ConnectionState> connectionSta
 | 
				
			|||||||
        // All connected clients are available in an std::set. See the broadcast cpp example.
 | 
					        // All connected clients are available in an std::set. See the broadcast cpp example.
 | 
				
			||||||
        // Second parameter tells whether we are sending the message in binary or text mode.
 | 
					        // Second parameter tells whether we are sending the message in binary or text mode.
 | 
				
			||||||
        // Here we send it in the same mode as it was received.
 | 
					        // Here we send it in the same mode as it was received.
 | 
				
			||||||
 | 
					        std::cout << "Received: " << msg->str << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        webSocket.send(msg->str, msg->binary);
 | 
					        webSocket.send(msg->str, msg->binary);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
);
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto res = server.listen();
 | 
					auto res = server.listen();
 | 
				
			||||||
if (!res.first)
 | 
					if (!res.first)
 | 
				
			||||||
@@ -401,6 +417,10 @@ if (!res.first)
 | 
				
			|||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Per message deflate connection is enabled by default. It can be disabled
 | 
				
			||||||
 | 
					// which might be helpful when running on low power devices such as a Rasbery Pi
 | 
				
			||||||
 | 
					server.disablePerMessageDeflate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Run the server in the background. Server can be stoped by calling server.stop()
 | 
					// Run the server in the background. Server can be stoped by calling server.stop()
 | 
				
			||||||
server.start();
 | 
					server.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,12 @@
 | 
				
			|||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mingw build quirks
 | 
				
			||||||
 | 
					#if defined(_WIN32) && defined(__GNUC__)
 | 
				
			||||||
 | 
					#define AI_NUMERICSERV NI_NUMERICSERV
 | 
				
			||||||
 | 
					#define AI_ADDRCONFIG LUP_ADDRCONFIG
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const int64_t DNSLookup::kDefaultWait = 1; // ms
 | 
					    const int64_t DNSLookup::kDefaultWait = 1; // ms
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,16 +10,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count,
 | 
					    uint32_t calculateRetryWaitMilliseconds(uint32_t retryCount,
 | 
				
			||||||
                                            uint32_t maxWaitBetweenReconnectionRetries)
 | 
					                                            uint32_t maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
 | 
					                                            uint32_t minWaitBetweenReconnectionRetries)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        uint32_t wait_time = (retry_count < 26) ? (std::pow(2, retry_count) * 100) : 0;
 | 
					        uint32_t waitTime = (retryCount < 26) ? (std::pow(2, retryCount) * 100) : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (wait_time > maxWaitBetweenReconnectionRetries || wait_time == 0)
 | 
					        if (waitTime < minWaitBetweenReconnectionRetries)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            wait_time = maxWaitBetweenReconnectionRetries;
 | 
					            waitTime = minWaitBetweenReconnectionRetries;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return wait_time;
 | 
					        if (waitTime > maxWaitBetweenReconnectionRetries || waitTime == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            waitTime = maxWaitBetweenReconnectionRetries;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return waitTime;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count,
 | 
					    uint32_t calculateRetryWaitMilliseconds(uint32_t retryCount,
 | 
				
			||||||
                                            uint32_t maxWaitBetweenReconnectionRetries);
 | 
					                                            uint32_t maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
 | 
					                                            uint32_t minWaitBetweenReconnectionRetries);
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -137,7 +137,7 @@ namespace ix
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                contentLength = std::stoi(headers["Content-Length"]);
 | 
					                contentLength = std::stoi(headers["Content-Length"]);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (std::exception)
 | 
					            catch (const std::exception&)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return std::make_tuple(
 | 
					                return std::make_tuple(
 | 
				
			||||||
                    false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
 | 
					                    false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,10 +20,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
 | 
				
			||||||
    const std::string HttpClient::kPost = "POST";
 | 
					    const std::string HttpClient::kPost = "POST";
 | 
				
			||||||
    const std::string HttpClient::kGet = "GET";
 | 
					    const std::string HttpClient::kGet = "GET";
 | 
				
			||||||
    const std::string HttpClient::kHead = "HEAD";
 | 
					    const std::string HttpClient::kHead = "HEAD";
 | 
				
			||||||
    const std::string HttpClient::kDel = "DEL";
 | 
					    const std::string HttpClient::kDelete = "DELETE";
 | 
				
			||||||
    const std::string HttpClient::kPut = "PUT";
 | 
					    const std::string HttpClient::kPut = "PUT";
 | 
				
			||||||
    const std::string HttpClient::kPatch = "PATCH";
 | 
					    const std::string HttpClient::kPatch = "PATCH";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -189,14 +190,14 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Set a default Accept header if none is present
 | 
					        // Set a default Accept header if none is present
 | 
				
			||||||
        if (headers.find("Accept") == headers.end())
 | 
					        if (args->extraHeaders.find("Accept") == args->extraHeaders.end())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ss << "Accept: */*"
 | 
					            ss << "Accept: */*"
 | 
				
			||||||
               << "\r\n";
 | 
					               << "\r\n";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Set a default User agent if none is present
 | 
					        // Set a default User agent if none is present
 | 
				
			||||||
        if (headers.find("User-Agent") == headers.end())
 | 
					        if (args->extraHeaders.find("User-Agent") == args->extraHeaders.end())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
					            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -557,9 +558,9 @@ namespace ix
 | 
				
			|||||||
        return request(url, kHead, std::string(), args);
 | 
					        return request(url, kHead, std::string(), args);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HttpResponsePtr HttpClient::del(const std::string& url, HttpRequestArgsPtr args)
 | 
					    HttpResponsePtr HttpClient::Delete(const std::string& url, HttpRequestArgsPtr args)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return request(url, kDel, std::string(), args);
 | 
					        return request(url, kDelete, std::string(), args);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HttpResponsePtr HttpClient::request(const std::string& url,
 | 
					    HttpResponsePtr HttpClient::request(const std::string& url,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        HttpResponsePtr get(const std::string& url, HttpRequestArgsPtr args);
 | 
					        HttpResponsePtr get(const std::string& url, HttpRequestArgsPtr args);
 | 
				
			||||||
        HttpResponsePtr head(const std::string& url, HttpRequestArgsPtr args);
 | 
					        HttpResponsePtr head(const std::string& url, HttpRequestArgsPtr args);
 | 
				
			||||||
        HttpResponsePtr del(const std::string& url, HttpRequestArgsPtr args);
 | 
					        HttpResponsePtr Delete(const std::string& url, HttpRequestArgsPtr args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        HttpResponsePtr post(const std::string& url,
 | 
					        HttpResponsePtr post(const std::string& url,
 | 
				
			||||||
                             const HttpParameters& httpParameters,
 | 
					                             const HttpParameters& httpParameters,
 | 
				
			||||||
@@ -94,7 +94,7 @@ namespace ix
 | 
				
			|||||||
        const static std::string kPost;
 | 
					        const static std::string kPost;
 | 
				
			||||||
        const static std::string kGet;
 | 
					        const static std::string kGet;
 | 
				
			||||||
        const static std::string kHead;
 | 
					        const static std::string kHead;
 | 
				
			||||||
        const static std::string kDel;
 | 
					        const static std::string kDelete;
 | 
				
			||||||
        const static std::string kPut;
 | 
					        const static std::string kPut;
 | 
				
			||||||
        const static std::string kPatch;
 | 
					        const static std::string kPatch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,4 +124,158 @@ namespace ix
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // mingw does not have inet_ntop, which were taken as is from the musl C library.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    const char* inet_ntop(int af, const void* a0, char* s, socklen_t l)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if defined(_WIN32) && defined(__GNUC__)
 | 
				
			||||||
 | 
					        const unsigned char* a = (const unsigned char*) a0;
 | 
				
			||||||
 | 
					        int i, j, max, best;
 | 
				
			||||||
 | 
					        char buf[100];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (af)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case AF_INET:
 | 
				
			||||||
 | 
					                if (snprintf(s, l, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]) < l) return s;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case AF_INET6:
 | 
				
			||||||
 | 
					                if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12))
 | 
				
			||||||
 | 
					                    snprintf(buf,
 | 
				
			||||||
 | 
					                             sizeof buf,
 | 
				
			||||||
 | 
					                             "%x:%x:%x:%x:%x:%x:%x:%x",
 | 
				
			||||||
 | 
					                             256 * a[0] + a[1],
 | 
				
			||||||
 | 
					                             256 * a[2] + a[3],
 | 
				
			||||||
 | 
					                             256 * a[4] + a[5],
 | 
				
			||||||
 | 
					                             256 * a[6] + a[7],
 | 
				
			||||||
 | 
					                             256 * a[8] + a[9],
 | 
				
			||||||
 | 
					                             256 * a[10] + a[11],
 | 
				
			||||||
 | 
					                             256 * a[12] + a[13],
 | 
				
			||||||
 | 
					                             256 * a[14] + a[15]);
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    snprintf(buf,
 | 
				
			||||||
 | 
					                             sizeof buf,
 | 
				
			||||||
 | 
					                             "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d",
 | 
				
			||||||
 | 
					                             256 * a[0] + a[1],
 | 
				
			||||||
 | 
					                             256 * a[2] + a[3],
 | 
				
			||||||
 | 
					                             256 * a[4] + a[5],
 | 
				
			||||||
 | 
					                             256 * a[6] + a[7],
 | 
				
			||||||
 | 
					                             256 * a[8] + a[9],
 | 
				
			||||||
 | 
					                             256 * a[10] + a[11],
 | 
				
			||||||
 | 
					                             a[12],
 | 
				
			||||||
 | 
					                             a[13],
 | 
				
			||||||
 | 
					                             a[14],
 | 
				
			||||||
 | 
					                             a[15]);
 | 
				
			||||||
 | 
					                /* Replace longest /(^0|:)[:0]{2,}/ with "::" */
 | 
				
			||||||
 | 
					                for (i = best = 0, max = 2; buf[i]; i++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (i && buf[i] != ':') continue;
 | 
				
			||||||
 | 
					                    j = strspn(buf + i, ":0");
 | 
				
			||||||
 | 
					                    if (j > max) best = i, max = j;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (max > 3)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    buf[best] = buf[best + 1] = ':';
 | 
				
			||||||
 | 
					                    memmove(buf + best + 2, buf + best + max, i - best - max + 1);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (strlen(buf) < l)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    strcpy(s, buf);
 | 
				
			||||||
 | 
					                    return s;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default: errno = EAFNOSUPPORT; return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        errno = ENOSPC;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        return ::inet_ntop(af, a0, s, l);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(_WIN32) && defined(__GNUC__)
 | 
				
			||||||
 | 
					    static int hexval(unsigned c)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (c - '0' < 10) return c - '0';
 | 
				
			||||||
 | 
					        c |= 32;
 | 
				
			||||||
 | 
					        if (c - 'a' < 6) return c - 'a' + 10;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // mingw does not have inet_pton, which were taken as is from the musl C library.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    int inet_pton(int af, const char* s, void* a0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if defined(_WIN32) && defined(__GNUC__)
 | 
				
			||||||
 | 
					        uint16_t ip[8];
 | 
				
			||||||
 | 
					        unsigned char* a = (unsigned char*) a0;
 | 
				
			||||||
 | 
					        int i, j, v, d, brk = -1, need_v4 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (af == AF_INET)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (i = 0; i < 4; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                for (v = j = 0; j < 3 && isdigit(s[j]); j++)
 | 
				
			||||||
 | 
					                    v = 10 * v + s[j] - '0';
 | 
				
			||||||
 | 
					                if (j == 0 || (j > 1 && s[0] == '0') || v > 255) return 0;
 | 
				
			||||||
 | 
					                a[i] = v;
 | 
				
			||||||
 | 
					                if (s[j] == 0 && i == 3) return 1;
 | 
				
			||||||
 | 
					                if (s[j] != '.') return 0;
 | 
				
			||||||
 | 
					                s += j + 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (af != AF_INET6)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errno = EAFNOSUPPORT;
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (*s == ':' && *++s != ':') return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (i = 0;; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (s[0] == ':' && brk < 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                brk = i;
 | 
				
			||||||
 | 
					                ip[i & 7] = 0;
 | 
				
			||||||
 | 
					                if (!*++s) break;
 | 
				
			||||||
 | 
					                if (i == 7) return 0;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++)
 | 
				
			||||||
 | 
					                v = 16 * v + d;
 | 
				
			||||||
 | 
					            if (j == 0) return 0;
 | 
				
			||||||
 | 
					            ip[i & 7] = v;
 | 
				
			||||||
 | 
					            if (!s[j] && (brk >= 0 || i == 7)) break;
 | 
				
			||||||
 | 
					            if (i == 7) return 0;
 | 
				
			||||||
 | 
					            if (s[j] != ':')
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (s[j] != '.' || (i < 6 && brk < 0)) return 0;
 | 
				
			||||||
 | 
					                need_v4 = 1;
 | 
				
			||||||
 | 
					                i++;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            s += j + 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (brk >= 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk));
 | 
				
			||||||
 | 
					            for (j = 0; j < 7 - i; j++)
 | 
				
			||||||
 | 
					                ip[brk + j] = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (j = 0; j < 8; j++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            *a++ = ip[j] >> 8;
 | 
				
			||||||
 | 
					            *a++ = ip[j];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (need_v4 && inet_pton(AF_INET, (const char*) s, a - 4) <= 0) return 0;
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        return ::inet_pton(af, s, a0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,15 +7,49 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef WIN32_LEAN_AND_MEAN
 | 
				
			||||||
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <WS2tcpip.h>
 | 
					#include <WS2tcpip.h>
 | 
				
			||||||
#include <WinSock2.h>
 | 
					#include <WinSock2.h>
 | 
				
			||||||
#include <basetsd.h>
 | 
					#include <basetsd.h>
 | 
				
			||||||
#include <io.h>
 | 
					#include <io.h>
 | 
				
			||||||
#include <ws2def.h>
 | 
					#include <ws2def.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef EWOULDBLOCK
 | 
				
			||||||
 | 
					#undef EAGAIN
 | 
				
			||||||
 | 
					#undef EINPROGRESS
 | 
				
			||||||
 | 
					#undef EBADF
 | 
				
			||||||
 | 
					#undef EINVAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// map to WSA error codes
 | 
				
			||||||
 | 
					#define EWOULDBLOCK WSAEWOULDBLOCK
 | 
				
			||||||
 | 
					#define EAGAIN WSATRY_AGAIN
 | 
				
			||||||
 | 
					#define EINPROGRESS WSAEINPROGRESS
 | 
				
			||||||
 | 
					#define EBADF WSAEBADF
 | 
				
			||||||
 | 
					#define EINVAL WSAEINVAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Define our own poll on Windows, as a wrapper on top of select
 | 
					// Define our own poll on Windows, as a wrapper on top of select
 | 
				
			||||||
typedef unsigned long int nfds_t;
 | 
					typedef unsigned long int nfds_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mingw does not know about poll so mock it
 | 
				
			||||||
 | 
					#if defined(__GNUC__)
 | 
				
			||||||
 | 
					struct pollfd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int fd;        /* file descriptor */
 | 
				
			||||||
 | 
					    short events;  /* requested events */
 | 
				
			||||||
 | 
					    short revents; /* returned events */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define POLLIN 0x001   /* There is data to read.  */
 | 
				
			||||||
 | 
					#define POLLOUT 0x004  /* Writing now will not block.  */
 | 
				
			||||||
 | 
					#define POLLERR 0x008  /* Error condition.  */
 | 
				
			||||||
 | 
					#define POLLHUP 0x010  /* Hung up.  */
 | 
				
			||||||
 | 
					#define POLLNVAL 0x020 /* Invalid polling request.  */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
@@ -44,4 +78,7 @@ namespace ix
 | 
				
			|||||||
    bool uninitNetSystem();
 | 
					    bool uninitNetSystem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int poll(struct pollfd* fds, nfds_t nfds, int timeout);
 | 
					    int poll(struct pollfd* fds, nfds_t nfds, int timeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char* inet_ntop(int af, const void* src, char* dst, socklen_t size);
 | 
				
			||||||
 | 
					    int inet_pton(int af, const char* src, void* dst);
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void SetThreadName(DWORD dwThreadID, const char* threadName)
 | 
					    void SetThreadName(DWORD dwThreadID, const char* threadName)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					#ifndef __GNUC__
 | 
				
			||||||
        THREADNAME_INFO info;
 | 
					        THREADNAME_INFO info;
 | 
				
			||||||
        info.dwType = 0x1000;
 | 
					        info.dwType = 0x1000;
 | 
				
			||||||
        info.szName = threadName;
 | 
					        info.szName = threadName;
 | 
				
			||||||
@@ -51,6 +52,7 @@ namespace ix
 | 
				
			|||||||
        __except (EXCEPTION_EXECUTE_HANDLER)
 | 
					        __except (EXCEPTION_EXECUTE_HANDLER)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,20 +15,6 @@
 | 
				
			|||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
#include <BaseTsd.h>
 | 
					#include <BaseTsd.h>
 | 
				
			||||||
typedef SSIZE_T ssize_t;
 | 
					typedef SSIZE_T ssize_t;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#undef EWOULDBLOCK
 | 
					 | 
				
			||||||
#undef EAGAIN
 | 
					 | 
				
			||||||
#undef EINPROGRESS
 | 
					 | 
				
			||||||
#undef EBADF
 | 
					 | 
				
			||||||
#undef EINVAL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// map to WSA error codes
 | 
					 | 
				
			||||||
#define EWOULDBLOCK WSAEWOULDBLOCK
 | 
					 | 
				
			||||||
#define EAGAIN WSATRY_AGAIN
 | 
					 | 
				
			||||||
#define EINPROGRESS WSAEINPROGRESS
 | 
					 | 
				
			||||||
#define EBADF WSAEBADF
 | 
					 | 
				
			||||||
#define EINVAL WSAEINVAL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCancellationRequest.h"
 | 
					#include "IXCancellationRequest.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,11 @@
 | 
				
			|||||||
#include "IXSocketConnect.h"
 | 
					#include "IXSocketConnect.h"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					// For manipulating the certificate store
 | 
				
			||||||
 | 
					#include <wincrypt.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SocketMbedTLS::SocketMbedTLS(const SocketTLSOptions& tlsOptions, int fd)
 | 
					    SocketMbedTLS::SocketMbedTLS(const SocketTLSOptions& tlsOptions, int fd)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,11 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#define socketerrno errno
 | 
					#define socketerrno errno
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					// For manipulating the certificate store
 | 
				
			||||||
 | 
					#include <wincrypt.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,7 +104,7 @@ namespace ix
 | 
				
			|||||||
            server.sin_family = _addressFamily;
 | 
					            server.sin_family = _addressFamily;
 | 
				
			||||||
            server.sin_port = htons(_port);
 | 
					            server.sin_port = htons(_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (inet_pton(_addressFamily, _host.c_str(), &server.sin_addr.s_addr) <= 0)
 | 
					            if (ix::inet_pton(_addressFamily, _host.c_str(), &server.sin_addr.s_addr) <= 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::stringstream ss;
 | 
					                std::stringstream ss;
 | 
				
			||||||
                ss << "SocketServer::listen() error calling inet_pton "
 | 
					                ss << "SocketServer::listen() error calling inet_pton "
 | 
				
			||||||
@@ -133,7 +133,7 @@ namespace ix
 | 
				
			|||||||
            server.sin6_family = _addressFamily;
 | 
					            server.sin6_family = _addressFamily;
 | 
				
			||||||
            server.sin6_port = htons(_port);
 | 
					            server.sin6_port = htons(_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (inet_pton(_addressFamily, _host.c_str(), &server.sin6_addr) <= 0)
 | 
					            if (ix::inet_pton(_addressFamily, _host.c_str(), &server.sin6_addr) <= 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::stringstream ss;
 | 
					                std::stringstream ss;
 | 
				
			||||||
                ss << "SocketServer::listen() error calling inet_pton "
 | 
					                ss << "SocketServer::listen() error calling inet_pton "
 | 
				
			||||||
@@ -338,7 +338,7 @@ namespace ix
 | 
				
			|||||||
            if (_addressFamily == AF_INET)
 | 
					            if (_addressFamily == AF_INET)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                char remoteIp4[INET_ADDRSTRLEN];
 | 
					                char remoteIp4[INET_ADDRSTRLEN];
 | 
				
			||||||
                if (inet_ntop(AF_INET, &client.sin_addr, remoteIp4, INET_ADDRSTRLEN) == nullptr)
 | 
					                if (ix::inet_ntop(AF_INET, &client.sin_addr, remoteIp4, INET_ADDRSTRLEN) == nullptr)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    int err = Socket::getErrno();
 | 
					                    int err = Socket::getErrno();
 | 
				
			||||||
                    std::stringstream ss;
 | 
					                    std::stringstream ss;
 | 
				
			||||||
@@ -357,7 +357,8 @@ namespace ix
 | 
				
			|||||||
            else // AF_INET6
 | 
					            else // AF_INET6
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                char remoteIp6[INET6_ADDRSTRLEN];
 | 
					                char remoteIp6[INET6_ADDRSTRLEN];
 | 
				
			||||||
                if (inet_ntop(AF_INET6, &client.sin_addr, remoteIp6, INET6_ADDRSTRLEN) == nullptr)
 | 
					                if (ix::inet_ntop(AF_INET6, &client.sin_addr, remoteIp6, INET6_ADDRSTRLEN) ==
 | 
				
			||||||
 | 
					                    nullptr)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    int err = Socket::getErrno();
 | 
					                    int err = Socket::getErrno();
 | 
				
			||||||
                    std::stringstream ss;
 | 
					                    std::stringstream ss;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ namespace ix
 | 
				
			|||||||
    bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char& c1,
 | 
					    bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char& c1,
 | 
				
			||||||
                                                        const unsigned char& c2) const
 | 
					                                                        const unsigned char& c2) const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#if defined(_WIN32) && !defined(__GNUC__)
 | 
				
			||||||
        return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale());
 | 
					        return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale());
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        return std::tolower(c1) < std::tolower(c2);
 | 
					        return std::tolower(c1) < std::tolower(c2);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,12 @@
 | 
				
			|||||||
#include <cmath>
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const std::string emptyMsg;
 | 
				
			||||||
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    OnTrafficTrackerCallback WebSocket::_onTrafficTrackerCallback = nullptr;
 | 
					    OnTrafficTrackerCallback WebSocket::_onTrafficTrackerCallback = nullptr;
 | 
				
			||||||
@@ -22,12 +28,14 @@ namespace ix
 | 
				
			|||||||
    const int WebSocket::kDefaultPingIntervalSecs(-1);
 | 
					    const int WebSocket::kDefaultPingIntervalSecs(-1);
 | 
				
			||||||
    const bool WebSocket::kDefaultEnablePong(true);
 | 
					    const bool WebSocket::kDefaultEnablePong(true);
 | 
				
			||||||
    const uint32_t WebSocket::kDefaultMaxWaitBetweenReconnectionRetries(10 * 1000); // 10s
 | 
					    const uint32_t WebSocket::kDefaultMaxWaitBetweenReconnectionRetries(10 * 1000); // 10s
 | 
				
			||||||
 | 
					    const uint32_t WebSocket::kDefaultMinWaitBetweenReconnectionRetries(1);         // 1 ms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocket::WebSocket()
 | 
					    WebSocket::WebSocket()
 | 
				
			||||||
        : _onMessageCallback(OnMessageCallback())
 | 
					        : _onMessageCallback(OnMessageCallback())
 | 
				
			||||||
        , _stop(false)
 | 
					        , _stop(false)
 | 
				
			||||||
        , _automaticReconnection(true)
 | 
					        , _automaticReconnection(true)
 | 
				
			||||||
        , _maxWaitBetweenReconnectionRetries(kDefaultMaxWaitBetweenReconnectionRetries)
 | 
					        , _maxWaitBetweenReconnectionRetries(kDefaultMaxWaitBetweenReconnectionRetries)
 | 
				
			||||||
 | 
					        , _minWaitBetweenReconnectionRetries(kDefaultMinWaitBetweenReconnectionRetries)
 | 
				
			||||||
        , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs)
 | 
					        , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs)
 | 
				
			||||||
        , _enablePong(kDefaultEnablePong)
 | 
					        , _enablePong(kDefaultEnablePong)
 | 
				
			||||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
					        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
				
			||||||
@@ -36,7 +44,7 @@ namespace ix
 | 
				
			|||||||
            [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(
 | 
				
			||||||
                    ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
 | 
					                    ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
 | 
				
			||||||
                                                      "",
 | 
					                                                      emptyMsg,
 | 
				
			||||||
                                                      wireSize,
 | 
					                                                      wireSize,
 | 
				
			||||||
                                                      WebSocketErrorInfo(),
 | 
					                                                      WebSocketErrorInfo(),
 | 
				
			||||||
                                                      WebSocketOpenInfo(),
 | 
					                                                      WebSocketOpenInfo(),
 | 
				
			||||||
@@ -56,13 +64,18 @@ namespace ix
 | 
				
			|||||||
        _url = url;
 | 
					        _url = url;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocket::setHandshakeTimeout(int handshakeTimeoutSecs)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _handshakeTimeoutSecs = handshakeTimeoutSecs;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void WebSocket::setExtraHeaders(const WebSocketHttpHeaders& headers)
 | 
					    void WebSocket::setExtraHeaders(const WebSocketHttpHeaders& headers)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
        _extraHeaders = headers;
 | 
					        _extraHeaders = headers;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const std::string& WebSocket::getUrl() const
 | 
					    const std::string WebSocket::getUrl() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
        return _url;
 | 
					        return _url;
 | 
				
			||||||
@@ -81,7 +94,7 @@ namespace ix
 | 
				
			|||||||
        _socketTLSOptions = socketTLSOptions;
 | 
					        _socketTLSOptions = socketTLSOptions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const WebSocketPerMessageDeflateOptions& WebSocket::getPerMessageDeflateOptions() const
 | 
					    const WebSocketPerMessageDeflateOptions WebSocket::getPerMessageDeflateOptions() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
        return _perMessageDeflateOptions;
 | 
					        return _perMessageDeflateOptions;
 | 
				
			||||||
@@ -131,12 +144,24 @@ namespace ix
 | 
				
			|||||||
        _maxWaitBetweenReconnectionRetries = maxWaitBetweenReconnectionRetries;
 | 
					        _maxWaitBetweenReconnectionRetries = maxWaitBetweenReconnectionRetries;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void WebSocket::setMinWaitBetweenReconnectionRetries(uint32_t minWaitBetweenReconnectionRetries)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
 | 
					        _minWaitBetweenReconnectionRetries = minWaitBetweenReconnectionRetries;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t WebSocket::getMaxWaitBetweenReconnectionRetries() const
 | 
					    uint32_t WebSocket::getMaxWaitBetweenReconnectionRetries() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
        return _maxWaitBetweenReconnectionRetries;
 | 
					        return _maxWaitBetweenReconnectionRetries;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t WebSocket::getMinWaitBetweenReconnectionRetries() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
 | 
					        return _minWaitBetweenReconnectionRetries;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void WebSocket::start()
 | 
					    void WebSocket::start()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (_thread.joinable()) return; // we've already been started
 | 
					        if (_thread.joinable()) return; // we've already been started
 | 
				
			||||||
@@ -198,7 +223,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        _onMessageCallback(ix::make_unique<WebSocketMessage>(
 | 
					        _onMessageCallback(ix::make_unique<WebSocketMessage>(
 | 
				
			||||||
            WebSocketMessageType::Open,
 | 
					            WebSocketMessageType::Open,
 | 
				
			||||||
            "",
 | 
					            emptyMsg,
 | 
				
			||||||
            0,
 | 
					            0,
 | 
				
			||||||
            WebSocketErrorInfo(),
 | 
					            WebSocketErrorInfo(),
 | 
				
			||||||
            WebSocketOpenInfo(status.uri, status.headers, status.protocol),
 | 
					            WebSocketOpenInfo(status.uri, status.headers, status.protocol),
 | 
				
			||||||
@@ -213,7 +238,9 @@ namespace ix
 | 
				
			|||||||
        return status;
 | 
					        return status;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket, int timeoutSecs)
 | 
					    WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket,
 | 
				
			||||||
 | 
					                                                   int timeoutSecs,
 | 
				
			||||||
 | 
					                                                   bool enablePerMessageDeflate)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::lock_guard<std::mutex> lock(_configMutex);
 | 
					            std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
@@ -221,7 +248,8 @@ namespace ix
 | 
				
			|||||||
                _perMessageDeflateOptions, _socketTLSOptions, _enablePong, _pingIntervalSecs);
 | 
					                _perMessageDeflateOptions, _socketTLSOptions, _enablePong, _pingIntervalSecs);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketInitResult status = _ws.connectToSocket(std::move(socket), timeoutSecs);
 | 
					        WebSocketInitResult status =
 | 
				
			||||||
 | 
					            _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate);
 | 
				
			||||||
        if (!status.success)
 | 
					        if (!status.success)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return status;
 | 
					            return status;
 | 
				
			||||||
@@ -229,7 +257,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        _onMessageCallback(
 | 
					        _onMessageCallback(
 | 
				
			||||||
            ix::make_unique<WebSocketMessage>(WebSocketMessageType::Open,
 | 
					            ix::make_unique<WebSocketMessage>(WebSocketMessageType::Open,
 | 
				
			||||||
                                              "",
 | 
					                                              emptyMsg,
 | 
				
			||||||
                                              0,
 | 
					                                              0,
 | 
				
			||||||
                                              WebSocketErrorInfo(),
 | 
					                                              WebSocketErrorInfo(),
 | 
				
			||||||
                                              WebSocketOpenInfo(status.uri, status.headers),
 | 
					                                              WebSocketOpenInfo(status.uri, status.headers),
 | 
				
			||||||
@@ -303,8 +331,10 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (_automaticReconnection)
 | 
					                if (_automaticReconnection)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    duration = millis(calculateRetryWaitMilliseconds(
 | 
					                    duration =
 | 
				
			||||||
                        retries++, _maxWaitBetweenReconnectionRetries));
 | 
					                        millis(calculateRetryWaitMilliseconds(retries++,
 | 
				
			||||||
 | 
					                                                              _maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
 | 
					                                                              _minWaitBetweenReconnectionRetries));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    connectErr.wait_time = duration.count();
 | 
					                    connectErr.wait_time = duration.count();
 | 
				
			||||||
                    connectErr.retries = retries;
 | 
					                    connectErr.retries = retries;
 | 
				
			||||||
@@ -314,7 +344,7 @@ namespace ix
 | 
				
			|||||||
                connectErr.http_status = status.http_status;
 | 
					                connectErr.http_status = status.http_status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _onMessageCallback(ix::make_unique<WebSocketMessage>(WebSocketMessageType::Error,
 | 
					                _onMessageCallback(ix::make_unique<WebSocketMessage>(WebSocketMessageType::Error,
 | 
				
			||||||
                                                                     "",
 | 
					                                                                     emptyMsg,
 | 
				
			||||||
                                                                     0,
 | 
					                                                                     0,
 | 
				
			||||||
                                                                     connectErr,
 | 
					                                                                     connectErr,
 | 
				
			||||||
                                                                     WebSocketOpenInfo(),
 | 
					                                                                     WebSocketOpenInfo(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,7 @@ namespace ix
 | 
				
			|||||||
        void enablePerMessageDeflate();
 | 
					        void enablePerMessageDeflate();
 | 
				
			||||||
        void disablePerMessageDeflate();
 | 
					        void disablePerMessageDeflate();
 | 
				
			||||||
        void addSubProtocol(const std::string& subProtocol);
 | 
					        void addSubProtocol(const std::string& subProtocol);
 | 
				
			||||||
 | 
					        void setHandshakeTimeout(int handshakeTimeoutSecs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Run asynchronously, by calling start and stop.
 | 
					        // Run asynchronously, by calling start and stop.
 | 
				
			||||||
        void start();
 | 
					        void start();
 | 
				
			||||||
@@ -91,8 +92,8 @@ namespace ix
 | 
				
			|||||||
        ReadyState getReadyState() const;
 | 
					        ReadyState getReadyState() const;
 | 
				
			||||||
        static std::string readyStateToString(ReadyState readyState);
 | 
					        static std::string readyStateToString(ReadyState readyState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const std::string& getUrl() const;
 | 
					        const std::string getUrl() const;
 | 
				
			||||||
        const WebSocketPerMessageDeflateOptions& getPerMessageDeflateOptions() const;
 | 
					        const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const;
 | 
				
			||||||
        int getPingInterval() const;
 | 
					        int getPingInterval() const;
 | 
				
			||||||
        size_t bufferedAmount() const;
 | 
					        size_t bufferedAmount() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,7 +101,9 @@ namespace ix
 | 
				
			|||||||
        void disableAutomaticReconnection();
 | 
					        void disableAutomaticReconnection();
 | 
				
			||||||
        bool isAutomaticReconnectionEnabled() const;
 | 
					        bool isAutomaticReconnectionEnabled() const;
 | 
				
			||||||
        void setMaxWaitBetweenReconnectionRetries(uint32_t maxWaitBetweenReconnectionRetries);
 | 
					        void setMaxWaitBetweenReconnectionRetries(uint32_t maxWaitBetweenReconnectionRetries);
 | 
				
			||||||
 | 
					        void setMinWaitBetweenReconnectionRetries(uint32_t minWaitBetweenReconnectionRetries);
 | 
				
			||||||
        uint32_t getMaxWaitBetweenReconnectionRetries() const;
 | 
					        uint32_t getMaxWaitBetweenReconnectionRetries() const;
 | 
				
			||||||
 | 
					        uint32_t getMinWaitBetweenReconnectionRetries() const;
 | 
				
			||||||
        const std::vector<std::string>& getSubProtocols();
 | 
					        const std::vector<std::string>& getSubProtocols();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
@@ -114,7 +117,9 @@ namespace ix
 | 
				
			|||||||
        static void invokeTrafficTrackerCallback(size_t size, bool incoming);
 | 
					        static void invokeTrafficTrackerCallback(size_t size, bool incoming);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Server
 | 
					        // Server
 | 
				
			||||||
        WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, int timeoutSecs);
 | 
					        WebSocketInitResult connectToSocket(std::unique_ptr<Socket>,
 | 
				
			||||||
 | 
					                                            int timeoutSecs,
 | 
				
			||||||
 | 
					                                            bool enablePerMessageDeflate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketTransport _ws;
 | 
					        WebSocketTransport _ws;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -137,7 +142,9 @@ namespace ix
 | 
				
			|||||||
        // Automatic reconnection
 | 
					        // Automatic reconnection
 | 
				
			||||||
        std::atomic<bool> _automaticReconnection;
 | 
					        std::atomic<bool> _automaticReconnection;
 | 
				
			||||||
        static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries;
 | 
					        static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries;
 | 
				
			||||||
 | 
					        static const uint32_t kDefaultMinWaitBetweenReconnectionRetries;
 | 
				
			||||||
        uint32_t _maxWaitBetweenReconnectionRetries;
 | 
					        uint32_t _maxWaitBetweenReconnectionRetries;
 | 
				
			||||||
 | 
					        uint32_t _minWaitBetweenReconnectionRetries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Make the sleeping in the automatic reconnection cancellable
 | 
					        // Make the sleeping in the automatic reconnection cancellable
 | 
				
			||||||
        std::mutex _sleepMutex;
 | 
					        std::mutex _sleepMutex;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,6 +204,9 @@ namespace ix
 | 
				
			|||||||
        // Check the value of the connection field
 | 
					        // Check the value of the connection field
 | 
				
			||||||
        // Some websocket servers (Go/Gorilla?) send lowercase values for the
 | 
					        // Some websocket servers (Go/Gorilla?) send lowercase values for the
 | 
				
			||||||
        // connection header, so do a case insensitive comparison
 | 
					        // connection header, so do a case insensitive comparison
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // See https://github.com/apache/thrift/commit/7c4bdf9914fcba6c89e0f69ae48b9675578f084a
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
        if (!insensitiveStringCompare(headers["connection"], "Upgrade"))
 | 
					        if (!insensitiveStringCompare(headers["connection"], "Upgrade"))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::stringstream ss;
 | 
					            std::stringstream ss;
 | 
				
			||||||
@@ -241,7 +244,8 @@ namespace ix
 | 
				
			|||||||
        return WebSocketInitResult(true, status, "", headers, path);
 | 
					        return WebSocketInitResult(true, status, "", headers, path);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs)
 | 
					    WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs,
 | 
				
			||||||
 | 
					                                                            bool enablePerMessageDeflate)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _requestInitCancellation = false;
 | 
					        _requestInitCancellation = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -295,7 +299,8 @@ namespace ix
 | 
				
			|||||||
            return sendErrorResponse(400, "Missing Upgrade header");
 | 
					            return sendErrorResponse(400, "Missing Upgrade header");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!insensitiveStringCompare(headers["upgrade"], "WebSocket"))
 | 
					        if (!insensitiveStringCompare(headers["upgrade"], "WebSocket") &&
 | 
				
			||||||
 | 
					            headers["Upgrade"] != "keep-alive, Upgrade") // special case for firefox
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return sendErrorResponse(400,
 | 
					            return sendErrorResponse(400,
 | 
				
			||||||
                                     "Invalid Upgrade header, "
 | 
					                                     "Invalid Upgrade header, "
 | 
				
			||||||
@@ -338,7 +343,7 @@ namespace ix
 | 
				
			|||||||
        WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(header);
 | 
					        WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(header);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // If the client has requested that extension,
 | 
					        // If the client has requested that extension,
 | 
				
			||||||
        if (webSocketPerMessageDeflateOptions.enabled())
 | 
					        if (webSocketPerMessageDeflateOptions.enabled() && enablePerMessageDeflate)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _enablePerMessageDeflate = true;
 | 
					            _enablePerMessageDeflate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ namespace ix
 | 
				
			|||||||
                                            int port,
 | 
					                                            int port,
 | 
				
			||||||
                                            int timeoutSecs);
 | 
					                                            int timeoutSecs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketInitResult serverHandshake(int timeoutSecs);
 | 
					        WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        std::string genRandomString(const int len);
 | 
					        std::string genRandomString(const int len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,18 @@ namespace ix
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            ;
 | 
					            ;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * @brief Deleted overload to prevent binding `str` to a temporary, which would cause
 | 
				
			||||||
 | 
					         * undefined behavior since class members don't extend lifetime beyond the constructor call.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        WebSocketMessage(WebSocketMessageType t,
 | 
				
			||||||
 | 
					                         std::string&& s,
 | 
				
			||||||
 | 
					                         size_t w,
 | 
				
			||||||
 | 
					                         WebSocketErrorInfo e,
 | 
				
			||||||
 | 
					                         WebSocketOpenInfo o,
 | 
				
			||||||
 | 
					                         WebSocketCloseInfo c,
 | 
				
			||||||
 | 
					                         bool b = false) = delete;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    using WebSocketMessagePtr = std::unique_ptr<WebSocketMessage>;
 | 
					    using WebSocketMessagePtr = std::unique_ptr<WebSocketMessage>;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,12 +14,12 @@ namespace ix
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    /// Default values as defined in the RFC
 | 
					    /// Default values as defined in the RFC
 | 
				
			||||||
    const uint8_t WebSocketPerMessageDeflateOptions::kDefaultServerMaxWindowBits = 15;
 | 
					    const uint8_t WebSocketPerMessageDeflateOptions::kDefaultServerMaxWindowBits = 15;
 | 
				
			||||||
    static const int minServerMaxWindowBits = 8;
 | 
					    static const uint8_t minServerMaxWindowBits = 8;
 | 
				
			||||||
    static const int maxServerMaxWindowBits = 15;
 | 
					    static const uint8_t maxServerMaxWindowBits = 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const uint8_t WebSocketPerMessageDeflateOptions::kDefaultClientMaxWindowBits = 15;
 | 
					    const uint8_t WebSocketPerMessageDeflateOptions::kDefaultClientMaxWindowBits = 15;
 | 
				
			||||||
    static const int minClientMaxWindowBits = 8;
 | 
					    static const uint8_t minClientMaxWindowBits = 8;
 | 
				
			||||||
    static const int maxClientMaxWindowBits = 15;
 | 
					    static const uint8_t maxClientMaxWindowBits = 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketPerMessageDeflateOptions::WebSocketPerMessageDeflateOptions(
 | 
					    WebSocketPerMessageDeflateOptions::WebSocketPerMessageDeflateOptions(
 | 
				
			||||||
        bool enabled,
 | 
					        bool enabled,
 | 
				
			||||||
@@ -85,11 +85,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (startsWith(token, "server_max_window_bits="))
 | 
					            if (startsWith(token, "server_max_window_bits="))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::string val = token.substr(token.find_last_of("=") + 1);
 | 
					                uint8_t x = strtol(token.substr(token.find_last_of("=") + 1).c_str(), nullptr, 10);
 | 
				
			||||||
                std::stringstream ss;
 | 
					 | 
				
			||||||
                ss << val;
 | 
					 | 
				
			||||||
                int x;
 | 
					 | 
				
			||||||
                ss >> x;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Sanitize values to be in the proper range [8, 15] in
 | 
					                // Sanitize values to be in the proper range [8, 15] in
 | 
				
			||||||
                // case a server would give us bogus values
 | 
					                // case a server would give us bogus values
 | 
				
			||||||
@@ -99,11 +95,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (startsWith(token, "client_max_window_bits="))
 | 
					            if (startsWith(token, "client_max_window_bits="))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::string val = token.substr(token.find_last_of("=") + 1);
 | 
					                uint8_t x = strtol(token.substr(token.find_last_of("=") + 1).c_str(), nullptr, 10);
 | 
				
			||||||
                std::stringstream ss;
 | 
					 | 
				
			||||||
                ss << val;
 | 
					 | 
				
			||||||
                int x;
 | 
					 | 
				
			||||||
                ss >> x;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Sanitize values to be in the proper range [8, 15] in
 | 
					                // Sanitize values to be in the proper range [8, 15] in
 | 
				
			||||||
                // case a server would give us bogus values
 | 
					                // case a server would give us bogus values
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,8 +39,8 @@ namespace ix
 | 
				
			|||||||
        bool _enabled;
 | 
					        bool _enabled;
 | 
				
			||||||
        bool _clientNoContextTakeover;
 | 
					        bool _clientNoContextTakeover;
 | 
				
			||||||
        bool _serverNoContextTakeover;
 | 
					        bool _serverNoContextTakeover;
 | 
				
			||||||
        int _clientMaxWindowBits;
 | 
					        uint8_t _clientMaxWindowBits;
 | 
				
			||||||
        int _serverMaxWindowBits;
 | 
					        uint8_t _serverMaxWindowBits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void sanitizeClientMaxWindowBits();
 | 
					        void sanitizeClientMaxWindowBits();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,8 @@ namespace ix
 | 
				
			|||||||
            _clients.insert(webSocket);
 | 
					            _clients.insert(webSocket);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto status = webSocket->connectToSocket(std::move(socket), _handshakeTimeoutSecs);
 | 
					        auto status = webSocket->connectToSocket(
 | 
				
			||||||
 | 
					            std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate);
 | 
				
			||||||
        if (status.success)
 | 
					        if (status.success)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Process incoming messages and execute callbacks
 | 
					            // Process incoming messages and execute callbacks
 | 
				
			||||||
@@ -175,39 +176,39 @@ namespace ix
 | 
				
			|||||||
    //
 | 
					    //
 | 
				
			||||||
    void WebSocketServer::makeBroadcastServer()
 | 
					    void WebSocketServer::makeBroadcastServer()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setOnClientMessageCallback(
 | 
					        setOnClientMessageCallback([this](std::shared_ptr<ConnectionState> connectionState,
 | 
				
			||||||
            [this](std::shared_ptr<ConnectionState> connectionState,
 | 
					                                          WebSocket& webSocket,
 | 
				
			||||||
                   WebSocket& webSocket,
 | 
					                                          const WebSocketMessagePtr& msg) {
 | 
				
			||||||
                   const WebSocketMessagePtr& msg) {
 | 
					            auto remoteIp = connectionState->getRemoteIp();
 | 
				
			||||||
                auto remoteIp = connectionState->getRemoteIp();
 | 
					            if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
                if (msg->type == ix::WebSocketMessageType::Message)
 | 
					            {
 | 
				
			||||||
 | 
					                for (auto&& client : getClients())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    for (auto&& client : getClients())
 | 
					                    if (client.get() != &webSocket)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        if (client.get() != &webSocket)
 | 
					                        client->send(msg->str, msg->binary);
 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            client->send(msg->str, msg->binary);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            do
 | 
					                        // Make sure the OS send buffer is flushed before moving on
 | 
				
			||||||
                            {
 | 
					                        do
 | 
				
			||||||
                                size_t bufferedAmount = client->bufferedAmount();
 | 
					                        {
 | 
				
			||||||
                                std::chrono::duration<double, std::milli> duration(500);
 | 
					                            std::chrono::duration<double, std::milli> duration(500);
 | 
				
			||||||
                                std::this_thread::sleep_for(duration);
 | 
					                            std::this_thread::sleep_for(duration);
 | 
				
			||||||
                            } while (client->bufferedAmount() != 0);
 | 
					                        } while (client->bufferedAmount() != 0);
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int WebSocketServer::listenAndStart()
 | 
					    bool WebSocketServer::listenAndStart()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto res = listen();
 | 
					        auto res = listen();
 | 
				
			||||||
        if (!res.first)
 | 
					        if (!res.first)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return 1;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        start();
 | 
					        start();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,7 @@ namespace ix
 | 
				
			|||||||
        std::set<std::shared_ptr<WebSocket>> getClients();
 | 
					        std::set<std::shared_ptr<WebSocket>> getClients();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void makeBroadcastServer();
 | 
					        void makeBroadcastServer();
 | 
				
			||||||
        int listenAndStart();
 | 
					        bool listenAndStart();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const static int kDefaultHandShakeTimeoutSecs;
 | 
					        const static int kDefaultHandShakeTimeoutSecs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -169,7 +169,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Server
 | 
					    // Server
 | 
				
			||||||
    WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket,
 | 
					    WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                                            int timeoutSecs)
 | 
					                                                            int timeoutSecs,
 | 
				
			||||||
 | 
					                                                            bool enablePerMessageDeflate)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
					        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,7 +187,7 @@ namespace ix
 | 
				
			|||||||
                                              _perMessageDeflateOptions,
 | 
					                                              _perMessageDeflateOptions,
 | 
				
			||||||
                                              _enablePerMessageDeflate);
 | 
					                                              _enablePerMessageDeflate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto result = webSocketHandshake.serverHandshake(timeoutSecs);
 | 
					        auto result = webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate);
 | 
				
			||||||
        if (result.success)
 | 
					        if (result.success)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            setReadyState(ReadyState::OPEN);
 | 
					            setReadyState(ReadyState::OPEN);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,7 +83,9 @@ namespace ix
 | 
				
			|||||||
                                         int timeoutSecs);
 | 
					                                         int timeoutSecs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Server
 | 
					        // Server
 | 
				
			||||||
        WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, int timeoutSecs);
 | 
					        WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket,
 | 
				
			||||||
 | 
					                                            int timeoutSecs,
 | 
				
			||||||
 | 
					                                            bool enablePerMessageDeflate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PollResult poll();
 | 
					        PollResult poll();
 | 
				
			||||||
        WebSocketSendInfo sendBinary(const std::string& message,
 | 
					        WebSocketSendInfo sendBinary(const std::string& message,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IX_WEBSOCKET_VERSION "11.0.8"
 | 
					#define IX_WEBSOCKET_VERSION "11.2.10"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								main.cpp
									
									
									
									
									
								
							@@ -9,10 +9,13 @@
 | 
				
			|||||||
 *  $ mkdir -p build ; cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install
 | 
					 *  $ mkdir -p build ; cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install
 | 
				
			||||||
 *  $ clang++ --std=c++14 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation
 | 
					 *  $ clang++ --std=c++14 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation
 | 
				
			||||||
 *  $ ./a.out
 | 
					 *  $ ./a.out
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Or use cmake -DBUILD_DEMO=ON option for other platform
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ixwebsocket/IXNetSystem.h>
 | 
					#include <ixwebsocket/IXNetSystem.h>
 | 
				
			||||||
#include <ixwebsocket/IXWebSocket.h>
 | 
					#include <ixwebsocket/IXWebSocket.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXUserAgent.h>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main()
 | 
					int main()
 | 
				
			||||||
@@ -23,9 +26,12 @@ int main()
 | 
				
			|||||||
    // Our websocket object
 | 
					    // Our websocket object
 | 
				
			||||||
    ix::WebSocket webSocket;
 | 
					    ix::WebSocket webSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Connect to a server with encryption
 | 
				
			||||||
 | 
					    // See https://machinezone.github.io/IXWebSocket/usage/#tls-support-and-configuration
 | 
				
			||||||
    std::string url("wss://echo.websocket.org");
 | 
					    std::string url("wss://echo.websocket.org");
 | 
				
			||||||
    webSocket.setUrl(url);
 | 
					    webSocket.setUrl(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::cout << ix::userAgent() << std::endl;
 | 
				
			||||||
    std::cout << "Connecting to " << url << "..." << std::endl;
 | 
					    std::cout << "Connecting to " << url << "..." << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Setup a callback to be fired (in a background thread, watch out for race conditions !)
 | 
					    // Setup a callback to be fired (in a background thread, watch out for race conditions !)
 | 
				
			||||||
@@ -35,10 +41,18 @@ int main()
 | 
				
			|||||||
            if (msg->type == ix::WebSocketMessageType::Message)
 | 
					            if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::cout << "received message: " << msg->str << std::endl;
 | 
					                std::cout << "received message: " << msg->str << std::endl;
 | 
				
			||||||
 | 
					                std::cout << "> " << std::flush;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (msg->type == ix::WebSocketMessageType::Open)
 | 
					            else if (msg->type == ix::WebSocketMessageType::Open)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                std::cout << "Connection established" << std::endl;
 | 
					                std::cout << "Connection established" << std::endl;
 | 
				
			||||||
 | 
					                std::cout << "> " << std::flush;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (msg->type == ix::WebSocketMessageType::Error)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // Maybe SSL is not configured properly
 | 
				
			||||||
 | 
					                std::cout << "Connection error: " << msg->errorInfo.reason << std::endl;
 | 
				
			||||||
 | 
					                std::cout << "> " << std::flush;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -49,13 +63,16 @@ int main()
 | 
				
			|||||||
    // Send a message to the server (default to TEXT mode)
 | 
					    // Send a message to the server (default to TEXT mode)
 | 
				
			||||||
    webSocket.send("hello world");
 | 
					    webSocket.send("hello world");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (true)
 | 
					    // Display a prompt
 | 
				
			||||||
    {
 | 
					    std::cout << "> " << std::flush;
 | 
				
			||||||
        std::string text;
 | 
					 | 
				
			||||||
        std::cout << "> " << std::flush;
 | 
					 | 
				
			||||||
        std::getline(std::cin, text);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string text;
 | 
				
			||||||
 | 
					    // Read text from the console and send messages in text mode.
 | 
				
			||||||
 | 
					    // Exit with Ctrl-D on Unix or Ctrl-Z on Windows.
 | 
				
			||||||
 | 
					    while (std::getline(std::cin, text))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        webSocket.send(text);
 | 
					        webSocket.send(text);
 | 
				
			||||||
 | 
					        std::cout << "> " << std::flush;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								makefile.dev
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								makefile.dev
									
									
									
									
									
								
							@@ -22,37 +22,37 @@ install: brew
 | 
				
			|||||||
# Default rule does not use python as that requires first time users to have Python3 installed
 | 
					# Default rule does not use python as that requires first time users to have Python3 installed
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
brew:
 | 
					brew:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -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 -GNinja -DCMAKE_UNITY_BUILD=OFF -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Docker default target. We've had problems with OpenSSL and TLS 1.3 (on the
 | 
					# Docker default target. We've had problems 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_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_ZLIB=OFF -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_ZLIB=OFF -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws:
 | 
					ws:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_unity:
 | 
					ws_unity:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. && ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_install:
 | 
					ws_install:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. -DUSE_TEST=0 && ninja install)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. -DUSE_TEST=0 && ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_install_release:
 | 
					ws_install_release:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. -DUSE_TEST=0 && ninja install)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. -DUSE_TEST=0 && ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_openssl_install:
 | 
					ws_openssl_install:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_OPEN_SSL=1 .. ; ninja install)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_OPEN_SSL=1 .. ; ninja install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_mbedtls:
 | 
					ws_mbedtls:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; make -j 4)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; make -j 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_no_ssl:
 | 
					ws_no_ssl:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_WS=1 .. ; make -j 4)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=Debug -DUSE_WS=1 .. ; make -j 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ws_no_python:
 | 
					ws_no_python:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j4 install)
 | 
						mkdir -p build && (cd build ; cmake -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j4 install)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uninstall:
 | 
					uninstall:
 | 
				
			||||||
	xargs rm -fv < build/install_manifest.txt
 | 
						xargs rm -fv < build/install_manifest.txt
 | 
				
			||||||
@@ -111,27 +111,27 @@ test_server:
 | 
				
			|||||||
	(cd test && npm i ws && node broadcast-server.js)
 | 
						(cd test && npm i ws && node broadcast-server.js)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test:
 | 
					test:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 ..)
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 ..)
 | 
				
			||||||
	(cd build ; ninja)
 | 
						(cd build ; ninja)
 | 
				
			||||||
	(cd build ; ninja test)
 | 
						(cd build ; ninja -v test)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_asan:
 | 
					test_asan:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer")
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer")
 | 
				
			||||||
	(cd build ; ninja)
 | 
						(cd build ; ninja)
 | 
				
			||||||
	(cd build ; ctest -V .)
 | 
						(cd build ; ctest -V .)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_tsan_mbedtls:
 | 
					test_tsan_mbedtls:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_MBED_TLS=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_MBED_TLS=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
 | 
				
			||||||
	(cd build ; ninja)
 | 
						(cd build ; ninja)
 | 
				
			||||||
	(cd build ; ninja test)
 | 
						(cd build ; ninja test)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_tsan_openssl:
 | 
					test_tsan_openssl:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja --DCMAKE_UNITY_BUILD=ON DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPENS_SSL=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_UNITY_BUILD=ON DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPENS_SSL=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
 | 
				
			||||||
	(cd build ; ninja)
 | 
						(cd build ; ninja)
 | 
				
			||||||
	(cd build ; ninja test)
 | 
						(cd build ; ninja test)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_tsan_sectransport:
 | 
					test_tsan_sectransport:
 | 
				
			||||||
	mkdir -p build && (cd build ; cmake -GNinja --DCMAKE_UNITY_BUILD=ON DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPENS_SSL=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
 | 
						mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPENS_SSL=1 -DUSE_TEST=1 .. -DCMAKE_C_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer")
 | 
				
			||||||
	(cd build ; ninja)
 | 
						(cd build ; ninja)
 | 
				
			||||||
	(cd build ; ninja test)
 | 
						(cd build ; ninja test)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,11 +33,7 @@ TEST_CASE("dns", "[net]")
 | 
				
			|||||||
        auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80);
 | 
					        auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        struct addrinfo* res = dnsLookup->resolve(errMsg,
 | 
					        struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
				
			||||||
                                                  []
 | 
					 | 
				
			||||||
                                                  {
 | 
					 | 
				
			||||||
                                                      return false;
 | 
					 | 
				
			||||||
                                                  });
 | 
					 | 
				
			||||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
					        std::cerr << "Error message: " << errMsg << std::endl;
 | 
				
			||||||
        REQUIRE(res == nullptr);
 | 
					        REQUIRE(res == nullptr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -48,11 +44,7 @@ TEST_CASE("dns", "[net]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        // The callback returning true means we are requesting cancellation
 | 
					        // The callback returning true means we are requesting cancellation
 | 
				
			||||||
        struct addrinfo* res = dnsLookup->resolve(errMsg,
 | 
					        struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; });
 | 
				
			||||||
                                                  []
 | 
					 | 
				
			||||||
                                                  {
 | 
					 | 
				
			||||||
                                                      return true;
 | 
					 | 
				
			||||||
                                                  });
 | 
					 | 
				
			||||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
					        std::cerr << "Error message: " << errMsg << std::endl;
 | 
				
			||||||
        REQUIRE(res == nullptr);
 | 
					        REQUIRE(res == nullptr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -139,8 +139,9 @@ namespace ix
 | 
				
			|||||||
        std::streamoff size = file.tellg();
 | 
					        std::streamoff size = file.tellg();
 | 
				
			||||||
        file.seekg(0, file.beg);
 | 
					        file.seekg(0, file.beg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        memblock.resize((size_t) size);
 | 
					        memblock.reserve((size_t) size);
 | 
				
			||||||
        file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
 | 
					        memblock.insert(
 | 
				
			||||||
 | 
					            memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return memblock;
 | 
					        return memblock;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5444
									
								
								third_party/cli11/CLI11.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5444
									
								
								third_party/cli11/CLI11.hpp
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5
									
								
								third_party/cpp-linenoise/linenoise.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								third_party/cpp-linenoise/linenoise.cpp
									
									
									
									
										vendored
									
									
								
							@@ -1639,7 +1639,10 @@ bool enableRawMode(int fd) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* Init windows console handles only once */
 | 
					        /* Init windows console handles only once */
 | 
				
			||||||
        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 | 
					        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 | 
				
			||||||
        if (hOut==INVALID_HANDLE_VALUE) goto fatal;
 | 
					        if (hOut==INVALID_HANDLE_VALUE) {
 | 
				
			||||||
 | 
					            errno = ENOTTY;
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DWORD consolemodeOut;
 | 
					    DWORD consolemodeOut;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										110
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -55,16 +55,17 @@ namespace
 | 
				
			|||||||
    std::pair<bool, std::vector<uint8_t>> load(const std::string& path)
 | 
					    std::pair<bool, std::vector<uint8_t>> load(const std::string& path)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::vector<uint8_t> memblock;
 | 
					        std::vector<uint8_t> memblock;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::ifstream file(path);
 | 
					        std::ifstream file(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!file.is_open()) return std::make_pair(false, memblock);
 | 
					        if (!file.is_open()) return std::make_pair(false, memblock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        file.seekg(0, file.end);
 | 
					        file.seekg(0, file.end);
 | 
				
			||||||
        std::streamoff size = file.tellg();
 | 
					        std::streamoff size = file.tellg();
 | 
				
			||||||
        file.seekg(0, file.beg);
 | 
					        file.seekg(0, file.beg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        memblock.resize((size_t) size);
 | 
					        memblock.reserve((size_t) size);
 | 
				
			||||||
        file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
 | 
					        memblock.insert(
 | 
				
			||||||
 | 
					            memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return std::make_pair(true, memblock);
 | 
					        return std::make_pair(true, memblock);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -86,9 +87,9 @@ namespace
 | 
				
			|||||||
        std::streamoff size = file.tellg();
 | 
					        std::streamoff size = file.tellg();
 | 
				
			||||||
        file.seekg(0, file.beg);
 | 
					        file.seekg(0, file.beg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        memblock.resize(size);
 | 
					        memblock.reserve((size_t) size);
 | 
				
			||||||
 | 
					        memblock.insert(
 | 
				
			||||||
        file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
 | 
					            memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string bytes(memblock.begin(), memblock.end());
 | 
					        std::string bytes(memblock.begin(), memblock.end());
 | 
				
			||||||
        return bytes;
 | 
					        return bytes;
 | 
				
			||||||
@@ -631,7 +632,8 @@ namespace ix
 | 
				
			|||||||
                         uint32_t maxWaitBetweenReconnectionRetries,
 | 
					                         uint32_t maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
                         const ix::SocketTLSOptions& tlsOptions,
 | 
					                         const ix::SocketTLSOptions& tlsOptions,
 | 
				
			||||||
                         const std::string& subprotocol,
 | 
					                         const std::string& subprotocol,
 | 
				
			||||||
                         int pingIntervalSecs);
 | 
					                         int pingIntervalSecs,
 | 
				
			||||||
 | 
					                         bool decompressGzipMessages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void subscribe(const std::string& channel);
 | 
					        void subscribe(const std::string& channel);
 | 
				
			||||||
        void start();
 | 
					        void start();
 | 
				
			||||||
@@ -656,6 +658,7 @@ namespace ix
 | 
				
			|||||||
        bool _binaryMode;
 | 
					        bool _binaryMode;
 | 
				
			||||||
        std::atomic<int> _receivedBytes;
 | 
					        std::atomic<int> _receivedBytes;
 | 
				
			||||||
        std::atomic<int> _sentBytes;
 | 
					        std::atomic<int> _sentBytes;
 | 
				
			||||||
 | 
					        bool _decompressGzipMessages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void log(const std::string& msg);
 | 
					        void log(const std::string& msg);
 | 
				
			||||||
        WebSocketHttpHeaders parseHeaders(const std::string& data);
 | 
					        WebSocketHttpHeaders parseHeaders(const std::string& data);
 | 
				
			||||||
@@ -669,12 +672,14 @@ namespace ix
 | 
				
			|||||||
                                       uint32_t maxWaitBetweenReconnectionRetries,
 | 
					                                       uint32_t maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
                                       const ix::SocketTLSOptions& tlsOptions,
 | 
					                                       const ix::SocketTLSOptions& tlsOptions,
 | 
				
			||||||
                                       const std::string& subprotocol,
 | 
					                                       const std::string& subprotocol,
 | 
				
			||||||
                                       int pingIntervalSecs)
 | 
					                                       int pingIntervalSecs,
 | 
				
			||||||
 | 
					                                       bool decompressGzipMessages)
 | 
				
			||||||
        : _url(url)
 | 
					        : _url(url)
 | 
				
			||||||
        , _disablePerMessageDeflate(disablePerMessageDeflate)
 | 
					        , _disablePerMessageDeflate(disablePerMessageDeflate)
 | 
				
			||||||
        , _binaryMode(binaryMode)
 | 
					        , _binaryMode(binaryMode)
 | 
				
			||||||
        , _receivedBytes(0)
 | 
					        , _receivedBytes(0)
 | 
				
			||||||
        , _sentBytes(0)
 | 
					        , _sentBytes(0)
 | 
				
			||||||
 | 
					        , _decompressGzipMessages(decompressGzipMessages)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (disableAutomaticReconnection)
 | 
					        if (disableAutomaticReconnection)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -783,7 +788,21 @@ namespace ix
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                spdlog::info("Received {} bytes", msg->wireSize);
 | 
					                spdlog::info("Received {} bytes", msg->wireSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ss << "ws_connect: received message: " << msg->str;
 | 
					                std::string payload = msg->str;
 | 
				
			||||||
 | 
					                if (_decompressGzipMessages)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    std::string decompressedBytes;
 | 
				
			||||||
 | 
					                    if (gzipDecompress(payload, decompressedBytes))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        payload = decompressedBytes;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        spdlog::error("Error decompressing: {}", payload);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ss << "ws_connect: received message: " << payload;
 | 
				
			||||||
                log(ss.str());
 | 
					                log(ss.str());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (msg->type == ix::WebSocketMessageType::Error)
 | 
					            else if (msg->type == ix::WebSocketMessageType::Error)
 | 
				
			||||||
@@ -836,7 +855,8 @@ namespace ix
 | 
				
			|||||||
                        uint32_t maxWaitBetweenReconnectionRetries,
 | 
					                        uint32_t maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
                        const ix::SocketTLSOptions& tlsOptions,
 | 
					                        const ix::SocketTLSOptions& tlsOptions,
 | 
				
			||||||
                        const std::string& subprotocol,
 | 
					                        const std::string& subprotocol,
 | 
				
			||||||
                        int pingIntervalSecs)
 | 
					                        int pingIntervalSecs,
 | 
				
			||||||
 | 
					                        bool decompressGzipMessages)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
 | 
					        std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
 | 
				
			||||||
        WebSocketConnect webSocketChat(url,
 | 
					        WebSocketConnect webSocketChat(url,
 | 
				
			||||||
@@ -847,7 +867,8 @@ namespace ix
 | 
				
			|||||||
                                       maxWaitBetweenReconnectionRetries,
 | 
					                                       maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
                                       tlsOptions,
 | 
					                                       tlsOptions,
 | 
				
			||||||
                                       subprotocol,
 | 
					                                       subprotocol,
 | 
				
			||||||
                                       pingIntervalSecs);
 | 
					                                       pingIntervalSecs,
 | 
				
			||||||
 | 
					                                       decompressGzipMessages);
 | 
				
			||||||
        webSocketChat.start();
 | 
					        webSocketChat.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (true)
 | 
					        while (true)
 | 
				
			||||||
@@ -901,8 +922,11 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        auto addr = res->ai_addr;
 | 
					        auto addr = res->ai_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // FIXME: this display weird addresses / we could steal libuv inet.c
 | 
				
			||||||
 | 
					        // code which display correct results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        char str[INET_ADDRSTRLEN];
 | 
					        char str[INET_ADDRSTRLEN];
 | 
				
			||||||
        inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN);
 | 
					        ix::inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        spdlog::info("host: {} ip: {}", hostname, str);
 | 
					        spdlog::info("host: {} ip: {}", hostname, str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1421,10 +1445,18 @@ namespace ix
 | 
				
			|||||||
                    filename = output;
 | 
					                    filename = output;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                spdlog::info("Writing to disk: {}", filename);
 | 
					                if (filename.empty())
 | 
				
			||||||
                std::ofstream out(filename);
 | 
					                {
 | 
				
			||||||
                out.write((char*) &response->body.front(), response->body.size());
 | 
					                    spdlog::error("Cannot save content to disk: No output file supplied, and not "
 | 
				
			||||||
                out.close();
 | 
					                                  "filename could be extracted from the url {}",
 | 
				
			||||||
 | 
					                                  url);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    spdlog::info("Writing to disk: {}", filename);
 | 
				
			||||||
 | 
					                    std::ofstream out(filename);
 | 
				
			||||||
 | 
					                    out << response->body;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -1881,7 +1913,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        spdlog::info("ws_receive: Writing to disk: {}", filenameTmp);
 | 
					        spdlog::info("ws_receive: Writing to disk: {}", filenameTmp);
 | 
				
			||||||
        std::ofstream out(filenameTmp);
 | 
					        std::ofstream out(filenameTmp);
 | 
				
			||||||
        out.write((char*) &content.front(), content.size());
 | 
					        std::string contentAsString(content.begin(), content.end());
 | 
				
			||||||
 | 
					        out << contentAsString;
 | 
				
			||||||
        out.close();
 | 
					        out.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        spdlog::info("ws_receive: Renaming {} to {}", filenameTmp, filename);
 | 
					        spdlog::info("ws_receive: Renaming {} to {}", filenameTmp, filename);
 | 
				
			||||||
@@ -2069,23 +2102,6 @@ namespace ix
 | 
				
			|||||||
        _condition.wait(lock);
 | 
					        _condition.wait(lock);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<uint8_t> load(const std::string& path)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::vector<uint8_t> memblock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::ifstream file(path);
 | 
					 | 
				
			||||||
        if (!file.is_open()) return memblock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        file.seekg(0, file.end);
 | 
					 | 
				
			||||||
        std::streamoff size = file.tellg();
 | 
					 | 
				
			||||||
        file.seekg(0, file.beg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        memblock.resize((size_t) size);
 | 
					 | 
				
			||||||
        file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return memblock;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void WebSocketSender::start()
 | 
					    void WebSocketSender::start()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _webSocket.setUrl(_url);
 | 
					        _webSocket.setUrl(_url);
 | 
				
			||||||
@@ -2179,7 +2195,8 @@ namespace ix
 | 
				
			|||||||
        std::vector<uint8_t> content;
 | 
					        std::vector<uint8_t> content;
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Bench bench("ws_send: load file from disk");
 | 
					            Bench bench("ws_send: load file from disk");
 | 
				
			||||||
            content = load(filename);
 | 
					            auto res = load(filename);
 | 
				
			||||||
 | 
					            content = res.second;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _id = uuid4();
 | 
					        _id = uuid4();
 | 
				
			||||||
@@ -2375,9 +2392,9 @@ namespace ix
 | 
				
			|||||||
                            else
 | 
					                            else
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                std::string readyStateString =
 | 
					                                std::string readyStateString =
 | 
				
			||||||
                                    readyState == ReadyState::Connecting
 | 
					                                    readyState == ReadyState::Connecting ? "Connecting"
 | 
				
			||||||
                                        ? "Connecting"
 | 
					                                    : readyState == ReadyState::Closing  ? "Closing"
 | 
				
			||||||
                                        : readyState == ReadyState::Closing ? "Closing" : "Closed";
 | 
					                                                                         : "Closed";
 | 
				
			||||||
                                size_t bufferedAmount = client->bufferedAmount();
 | 
					                                size_t bufferedAmount = client->bufferedAmount();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                spdlog::info(
 | 
					                                spdlog::info(
 | 
				
			||||||
@@ -2490,9 +2507,10 @@ int main(int argc, char** argv)
 | 
				
			|||||||
    int delayMs = -1;
 | 
					    int delayMs = -1;
 | 
				
			||||||
    int count = 1;
 | 
					    int count = 1;
 | 
				
			||||||
    int msgCount = 1000 * 1000;
 | 
					    int msgCount = 1000 * 1000;
 | 
				
			||||||
    uint32_t maxWaitBetweenReconnectionRetries;
 | 
					    uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds
 | 
				
			||||||
    int pingIntervalSecs = 30;
 | 
					    int pingIntervalSecs = 30;
 | 
				
			||||||
    int runCount = 1;
 | 
					    int runCount = 1;
 | 
				
			||||||
 | 
					    bool decompressGzipMessages = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto addGenericOptions = [&pidfile](CLI::App* app) {
 | 
					    auto addGenericOptions = [&pidfile](CLI::App* app) {
 | 
				
			||||||
        app->add_option("--pidfile", pidfile, "Pid file");
 | 
					        app->add_option("--pidfile", pidfile, "Pid file");
 | 
				
			||||||
@@ -2555,6 +2573,7 @@ int main(int argc, char** argv)
 | 
				
			|||||||
                           "Max Wait Time between reconnection retries");
 | 
					                           "Max Wait Time between reconnection retries");
 | 
				
			||||||
    connectApp->add_option("--ping_interval", pingIntervalSecs, "Interval between sending pings");
 | 
					    connectApp->add_option("--ping_interval", pingIntervalSecs, "Interval between sending pings");
 | 
				
			||||||
    connectApp->add_option("--subprotocol", subprotocol, "Subprotocol");
 | 
					    connectApp->add_option("--subprotocol", subprotocol, "Subprotocol");
 | 
				
			||||||
 | 
					    connectApp->add_flag("-g", decompressGzipMessages, "Decompress gziped messages");
 | 
				
			||||||
    addGenericOptions(connectApp);
 | 
					    addGenericOptions(connectApp);
 | 
				
			||||||
    addTLSOptions(connectApp);
 | 
					    addTLSOptions(connectApp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2743,7 +2762,8 @@ int main(int argc, char** argv)
 | 
				
			|||||||
                                  maxWaitBetweenReconnectionRetries,
 | 
					                                  maxWaitBetweenReconnectionRetries,
 | 
				
			||||||
                                  tlsOptions,
 | 
					                                  tlsOptions,
 | 
				
			||||||
                                  subprotocol,
 | 
					                                  subprotocol,
 | 
				
			||||||
                                  pingIntervalSecs);
 | 
					                                  pingIntervalSecs,
 | 
				
			||||||
 | 
					                                  decompressGzipMessages);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (app.got_subcommand("autoroute"))
 | 
					    else if (app.got_subcommand("autoroute"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -2771,8 +2791,14 @@ int main(int argc, char** argv)
 | 
				
			|||||||
        ix::WebSocketServer server(port, hostname);
 | 
					        ix::WebSocketServer server(port, hostname);
 | 
				
			||||||
        server.setTLSOptions(tlsOptions);
 | 
					        server.setTLSOptions(tlsOptions);
 | 
				
			||||||
        server.makeBroadcastServer();
 | 
					        server.makeBroadcastServer();
 | 
				
			||||||
        server.listenAndStart();
 | 
					        if (!server.listenAndStart())
 | 
				
			||||||
        server.wait();
 | 
					        {
 | 
				
			||||||
 | 
					            spdlog::error("Error while starting the server");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            server.wait();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (app.got_subcommand("send"))
 | 
					    else if (app.got_subcommand("send"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user