Compare commits
	
		
			6 Commits
		
	
	
		
			v11.2.8
			...
			feature/ci
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 84163ad19e | ||
|  | 5e5b7c34ca | ||
|  | 9bb1de64a4 | ||
|  | df9889947d | ||
|  | 6ede8c85b0 | ||
|  | 2663f605f4 | 
							
								
								
									
										2
									
								
								.github/workflows/mkdocs.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/mkdocs.yml
									
									
									
									
										vendored
									
									
								
							| @@ -21,7 +21,5 @@ jobs: | ||||
|         pip install pygments | ||||
|     - name: Build doc | ||||
|       run: | | ||||
|         git clean -dfx . | ||||
|         git fetch | ||||
|         git pull | ||||
|         mkdocs gh-deploy | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_linux.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_linux.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ name: linux | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|     - './**' | ||||
|  | ||||
| jobs: | ||||
|   linux: | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_linux_asan.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_linux_asan.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ name: linux_asan | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|     - './**' | ||||
|  | ||||
| jobs: | ||||
|   linux: | ||||
|   | ||||
| @@ -2,7 +2,7 @@ name: mac_tsan_mbedtls | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|     - './**' | ||||
|  | ||||
| jobs: | ||||
|   mac_tsan_mbedtls: | ||||
|   | ||||
| @@ -2,7 +2,7 @@ name: mac_tsan_openssl | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|     - './**' | ||||
|  | ||||
| jobs: | ||||
|   mac_tsan_openssl: | ||||
|   | ||||
| @@ -2,7 +2,7 @@ name: mac_tsan_sectransport | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|     - './**' | ||||
|  | ||||
| jobs: | ||||
|   mac_tsan_sectransport: | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_uwp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_uwp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ name: uwp | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|     - './**' | ||||
|  | ||||
| jobs: | ||||
|   uwp: | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_windows.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_windows.yml
									
									
									
									
										vendored
									
									
								
							| @@ -14,7 +14,7 @@ jobs: | ||||
|     - run: | | ||||
|         mkdir build | ||||
|         cd build | ||||
|         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 .. | ||||
|         cmake -GNinja -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 -DUSE_ZLIB=0 .. | ||||
|     - run: | | ||||
|         cd build | ||||
|         ninja | ||||
|   | ||||
							
								
								
									
										27
									
								
								.github/workflows/unittest_windows_gcc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								.github/workflows/unittest_windows_gcc.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | ||||
| name: windows_gcc | ||||
| on: | ||||
|   push: | ||||
|     paths-ignore: | ||||
|     - 'docs/**' | ||||
|  | ||||
| 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,4 +7,3 @@ ws/.certs/ | ||||
| ws/.srl | ||||
| ixhttpd | ||||
| makefile | ||||
| a.out | ||||
|   | ||||
| @@ -12,8 +12,6 @@ set (CMAKE_CXX_STANDARD 11) | ||||
| set (CXX_STANDARD_REQUIRED ON) | ||||
| set (CMAKE_CXX_EXTENSIONS OFF) | ||||
|  | ||||
| option (BUILD_DEMO OFF) | ||||
|  | ||||
| if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") | ||||
|   set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||||
| endif() | ||||
| @@ -88,7 +86,6 @@ set( IXWEBSOCKET_HEADERS | ||||
|     ixwebsocket/IXSocketTLSOptions.h | ||||
|     ixwebsocket/IXStrCaseCompare.h | ||||
|     ixwebsocket/IXUdpSocket.h | ||||
|     ixwebsocket/IXUniquePtr.h | ||||
|     ixwebsocket/IXUrlParser.h | ||||
|     ixwebsocket/IXUuid.h | ||||
|     ixwebsocket/IXUtf8Validator.h | ||||
| @@ -114,7 +111,6 @@ set( IXWEBSOCKET_HEADERS | ||||
|     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) | ||||
|  | ||||
| if (USE_TLS) | ||||
| @@ -148,7 +144,7 @@ if (USE_TLS) | ||||
|     endif() | ||||
| endif() | ||||
|  | ||||
| add_library( ixwebsocket | ||||
| add_library( ixwebsocket STATIC | ||||
|     ${IXWEBSOCKET_SOURCES} | ||||
|     ${IXWEBSOCKET_HEADERS} | ||||
| ) | ||||
| @@ -195,7 +191,7 @@ if (USE_TLS) | ||||
|     target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES}) | ||||
|   elseif (USE_SECURE_TRANSPORT) | ||||
|     message(STATUS "TLS configured to use secure transport") | ||||
|     target_link_libraries(ixwebsocket "-framework Foundation" "-framework Security") | ||||
|     target_link_libraries(ixwebsocket "-framework foundation" "-framework security") | ||||
|   endif() | ||||
| endif() | ||||
|  | ||||
| @@ -277,8 +273,3 @@ if (USE_WS OR USE_TEST) | ||||
|     add_subdirectory(test) | ||||
|   endif() | ||||
| endif() | ||||
|  | ||||
| if (BUILD_DEMO)  | ||||
|   add_executable(demo main.cpp) | ||||
|   target_link_libraries(demo ixwebsocket)  | ||||
| endif() | ||||
|   | ||||
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							| @@ -15,16 +15,13 @@ 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. | ||||
|  * | ||||
|  *  On macOS | ||||
|  *  $ mkdir -p build ; (cd build ; cmake -DUSE_TLS=1 .. ; make -j ; make install) | ||||
|  *  $ clang++ --std=c++11 --stdlib=libc++ main.cpp -lixwebsocket -lz -framework Security -framework Foundation | ||||
|  *  $ 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 | ||||
|  *  $ ./a.out | ||||
|  * | ||||
|  *  Or use cmake -DBUILD_DEMO=ON option for other platforms | ||||
|  */ | ||||
|  | ||||
| #include <ixwebsocket/IXNetSystem.h> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <ixwebsocket/IXUserAgent.h> | ||||
| #include <iostream> | ||||
|  | ||||
| int main() | ||||
| @@ -35,8 +32,6 @@ int main() | ||||
|     // Our websocket object | ||||
|     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"); | ||||
|     webSocket.setUrl(url); | ||||
|  | ||||
| @@ -49,18 +44,10 @@ int main() | ||||
|             if (msg->type == ix::WebSocketMessageType::Message) | ||||
|             { | ||||
|                 std::cout << "received message: " << msg->str << std::endl; | ||||
|                 std::cout << "> " << std::flush; | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Open) | ||||
|             { | ||||
|                 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; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| @@ -71,16 +58,13 @@ int main() | ||||
|     // Send a message to the server (default to TEXT mode) | ||||
|     webSocket.send("hello world"); | ||||
|  | ||||
|     // Display a prompt | ||||
|     std::cout << "> " << std::flush; | ||||
|  | ||||
|     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)) | ||||
|     while (true) | ||||
|     { | ||||
|         webSocket.send(text); | ||||
|         std::string text; | ||||
|         std::cout << "> " << std::flush; | ||||
|         std::getline(std::cin, text); | ||||
|  | ||||
|         webSocket.send(text); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| @@ -93,8 +77,6 @@ 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. | ||||
|  | ||||
| Starting with the 11.0.8 release, IXWebSocket should be fully C++11 compatible. | ||||
|  | ||||
| ## Users | ||||
|  | ||||
| If your company or project is using this library, feel free to open an issue or PR to amend this list. | ||||
| @@ -105,7 +87,6 @@ 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 | ||||
| - [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 | ||||
| - [Teleport](http://teleportconnect.com/), Teleport is your own personal remote robot avatar | ||||
|  | ||||
| ## Alternative libraries | ||||
|  | ||||
| @@ -115,7 +96,6 @@ There are plenty of great websocket libraries out there, which might work for yo | ||||
| * [beast](https://github.com/boostorg/beast) - C++ | ||||
| * [libwebsockets](https://libwebsockets.org/) - 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. | ||||
|  | ||||
| @@ -132,11 +112,6 @@ To check the performance of a websocket library, you can look at the [autoroute] | ||||
| | Windows           | Disabled          | None              | [![Build2][5]][0] | | ||||
| | UWP               | Disabled          | None              | [![Build2][6]][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  | ||||
| * Some tests are disabled on Windows/UWP because of a pathing problem | ||||
| * TLS and ZLIB are disabled on Windows/UWP because enabling make the CI run takes a lot of time, for setting up vcpkg. | ||||
|  | ||||
| [0]: https://github.com/machinezone/IXWebSocket | ||||
| [1]: https://github.com/machinezone/IXWebSocket/workflows/linux/badge.svg | ||||
| @@ -146,5 +121,4 @@ To check the performance of a websocket library, you can look at the [autoroute] | ||||
| [5]: https://github.com/machinezone/IXWebSocket/workflows/windows/badge.svg | ||||
| [6]: https://github.com/machinezone/IXWebSocket/workflows/uwp/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,66 +2,6 @@ | ||||
|  | ||||
| All changes to this project will be documented in this file. | ||||
|  | ||||
| ## [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 | ||||
|  | ||||
| (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: | ||||
|  | ||||
| * `-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_TLS=1` will enable TLS support | ||||
| * `-DUSE_OPEN_SSL=1` will use [openssl](https://www.openssl.org/) for the TLS support (default on Linux and Windows) | ||||
| * `-DUSE_MBED_TLS=1` will use [mbedlts](https://tls.mbed.org/) for the TLS support | ||||
| * `-DUSE_WS=1` will build the ws interactive command line tool | ||||
| * `-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. | ||||
|  | ||||
|   | ||||
| @@ -256,24 +256,11 @@ Wait time(ms): 6400 | ||||
| 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 minimum waiting time can also be set. | ||||
| The waiting time is capped by default at 10s between 2 attempts, but that value can be changed and queried. | ||||
|  | ||||
| ```cpp | ||||
| webSocket.setMaxWaitBetweenReconnectionRetries(5 * 1000); // 5000ms = 5s | ||||
| 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 | ||||
| @@ -347,10 +334,6 @@ if (!res.first) | ||||
|     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() | ||||
| server.start(); | ||||
|  | ||||
| @@ -374,10 +357,13 @@ 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. | ||||
| ix::WebSocketServer server(port); | ||||
|  | ||||
| server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) { | ||||
| server.setOnClientMessageCallback(std::shared_ptr<ConnectionState> connectionState, | ||||
|                                   WebSocket& webSocket, | ||||
|                                   const WebSocketMessagePtr& msg) | ||||
| { | ||||
|     // The ConnectionState object contains information about the connection, | ||||
|     // at this point only the client ip address and the port. | ||||
|     std::cout << "Remote ip: " << connectionState->getRemoteIp() << std::endl; | ||||
|     std::cout << "Remote ip: " << connectionState->getRemoteIp(); | ||||
|  | ||||
|     if (msg->type == ix::WebSocketMessageType::Open) | ||||
|     { | ||||
| @@ -395,7 +381,7 @@ server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connec | ||||
|         std::cout << "Headers:" << std::endl; | ||||
|         for (auto it : msg->openInfo.headers) | ||||
|         { | ||||
|             std::cout << "\t" << it.first << ": " << it.second << std::endl; | ||||
|             std::cout << it.first << ": " << it.second << std::endl; | ||||
|         } | ||||
|     } | ||||
|     else if (msg->type == ix::WebSocketMessageType::Message) | ||||
| @@ -404,11 +390,9 @@ server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connec | ||||
|         // 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. | ||||
|         // 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); | ||||
|     } | ||||
| }); | ||||
| ); | ||||
|  | ||||
| auto res = server.listen(); | ||||
| if (!res.first) | ||||
| @@ -417,10 +401,6 @@ if (!res.first) | ||||
|     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() | ||||
| server.start(); | ||||
|  | ||||
|   | ||||
| @@ -24,12 +24,6 @@ | ||||
| #include <string.h> | ||||
| #include <thread> | ||||
|  | ||||
| // mingw build quirks | ||||
| #if defined(_WIN32) && defined(__GNUC__) | ||||
| #define AI_NUMERICSERV NI_NUMERICSERV | ||||
| #define AI_ADDRCONFIG LUP_ADDRCONFIG | ||||
| #endif | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     const int64_t DNSLookup::kDefaultWait = 1; // ms | ||||
|   | ||||
| @@ -10,22 +10,16 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     uint32_t calculateRetryWaitMilliseconds(uint32_t retryCount, | ||||
|                                             uint32_t maxWaitBetweenReconnectionRetries, | ||||
|                                             uint32_t minWaitBetweenReconnectionRetries) | ||||
|     uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count, | ||||
|                                             uint32_t maxWaitBetweenReconnectionRetries) | ||||
|     { | ||||
|         uint32_t waitTime = (retryCount < 26) ? (std::pow(2, retryCount) * 100) : 0; | ||||
|         uint32_t wait_time = (retry_count < 26) ? (std::pow(2, retry_count) * 100) : 0; | ||||
|  | ||||
|         if (waitTime < minWaitBetweenReconnectionRetries) | ||||
|         if (wait_time > maxWaitBetweenReconnectionRetries || wait_time == 0) | ||||
|         { | ||||
|             waitTime = minWaitBetweenReconnectionRetries; | ||||
|             wait_time = maxWaitBetweenReconnectionRetries; | ||||
|         } | ||||
|  | ||||
|         if (waitTime > maxWaitBetweenReconnectionRetries || waitTime == 0) | ||||
|         { | ||||
|             waitTime = maxWaitBetweenReconnectionRetries; | ||||
|         } | ||||
|  | ||||
|         return waitTime; | ||||
|         return wait_time; | ||||
|     } | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -10,7 +10,6 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     uint32_t calculateRetryWaitMilliseconds(uint32_t retryCount, | ||||
|                                             uint32_t maxWaitBetweenReconnectionRetries, | ||||
|                                             uint32_t minWaitBetweenReconnectionRetries); | ||||
|     uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count, | ||||
|                                             uint32_t maxWaitBetweenReconnectionRetries); | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -137,7 +137,7 @@ namespace ix | ||||
|             { | ||||
|                 contentLength = std::stoi(headers["Content-Length"]); | ||||
|             } | ||||
|             catch (const std::exception&) | ||||
|             catch (std::exception) | ||||
|             { | ||||
|                 return std::make_tuple( | ||||
|                     false, "Error parsing HTTP Header 'Content-Length'", httpRequest); | ||||
|   | ||||
| @@ -20,11 +20,10 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods | ||||
|     const std::string HttpClient::kPost = "POST"; | ||||
|     const std::string HttpClient::kGet = "GET"; | ||||
|     const std::string HttpClient::kHead = "HEAD"; | ||||
|     const std::string HttpClient::kDelete = "DELETE"; | ||||
|     const std::string HttpClient::kDel = "DEL"; | ||||
|     const std::string HttpClient::kPut = "PUT"; | ||||
|     const std::string HttpClient::kPatch = "PATCH"; | ||||
|  | ||||
| @@ -558,9 +557,9 @@ namespace ix | ||||
|         return request(url, kHead, std::string(), args); | ||||
|     } | ||||
|  | ||||
|     HttpResponsePtr HttpClient::Delete(const std::string& url, HttpRequestArgsPtr args) | ||||
|     HttpResponsePtr HttpClient::del(const std::string& url, HttpRequestArgsPtr args) | ||||
|     { | ||||
|         return request(url, kDelete, std::string(), args); | ||||
|         return request(url, kDel, std::string(), args); | ||||
|     } | ||||
|  | ||||
|     HttpResponsePtr HttpClient::request(const std::string& url, | ||||
|   | ||||
| @@ -30,7 +30,7 @@ namespace ix | ||||
|  | ||||
|         HttpResponsePtr get(const std::string& url, HttpRequestArgsPtr args); | ||||
|         HttpResponsePtr head(const std::string& url, HttpRequestArgsPtr args); | ||||
|         HttpResponsePtr Delete(const std::string& url, HttpRequestArgsPtr args); | ||||
|         HttpResponsePtr del(const std::string& url, HttpRequestArgsPtr args); | ||||
|  | ||||
|         HttpResponsePtr post(const std::string& url, | ||||
|                              const HttpParameters& httpParameters, | ||||
| @@ -94,7 +94,7 @@ namespace ix | ||||
|         const static std::string kPost; | ||||
|         const static std::string kGet; | ||||
|         const static std::string kHead; | ||||
|         const static std::string kDelete; | ||||
|         const static std::string kDel; | ||||
|         const static std::string kPut; | ||||
|         const static std::string kPatch; | ||||
|  | ||||
|   | ||||
| @@ -124,158 +124,4 @@ namespace ix | ||||
| #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 | ||||
|   | ||||
| @@ -7,49 +7,15 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef _WIN32 | ||||
|  | ||||
| #ifndef WIN32_LEAN_AND_MEAN | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
| #endif | ||||
|  | ||||
| #include <WS2tcpip.h> | ||||
| #include <WinSock2.h> | ||||
| #include <basetsd.h> | ||||
| #include <io.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 | ||||
| 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 | ||||
| #include <arpa/inet.h> | ||||
| #include <errno.h> | ||||
| @@ -78,7 +44,4 @@ namespace ix | ||||
|     bool uninitNetSystem(); | ||||
|  | ||||
|     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 | ||||
|   | ||||
| @@ -37,7 +37,6 @@ namespace ix | ||||
|  | ||||
|     void SetThreadName(DWORD dwThreadID, const char* threadName) | ||||
|     { | ||||
| #ifndef __GNUC__ | ||||
|         THREADNAME_INFO info; | ||||
|         info.dwType = 0x1000; | ||||
|         info.szName = threadName; | ||||
| @@ -52,7 +51,6 @@ namespace ix | ||||
|         __except (EXCEPTION_EXECUTE_HANDLER) | ||||
|         { | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,20 @@ | ||||
| #ifdef _WIN32 | ||||
| #include <BaseTsd.h> | ||||
| 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 | ||||
|  | ||||
| #include "IXCancellationRequest.h" | ||||
|   | ||||
| @@ -16,11 +16,6 @@ | ||||
| #include "IXSocketConnect.h" | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| // For manipulating the certificate store | ||||
| #include <wincrypt.h> | ||||
| #endif | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     SocketMbedTLS::SocketMbedTLS(const SocketTLSOptions& tlsOptions, int fd) | ||||
|   | ||||
| @@ -24,11 +24,6 @@ | ||||
| #endif | ||||
| #define socketerrno errno | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| // For manipulating the certificate store | ||||
| #include <wincrypt.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| namespace | ||||
| { | ||||
|   | ||||
| @@ -104,7 +104,7 @@ namespace ix | ||||
|             server.sin_family = _addressFamily; | ||||
|             server.sin_port = htons(_port); | ||||
|  | ||||
|             if (ix::inet_pton(_addressFamily, _host.c_str(), &server.sin_addr.s_addr) <= 0) | ||||
|             if (inet_pton(_addressFamily, _host.c_str(), &server.sin_addr.s_addr) <= 0) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 ss << "SocketServer::listen() error calling inet_pton " | ||||
| @@ -133,7 +133,7 @@ namespace ix | ||||
|             server.sin6_family = _addressFamily; | ||||
|             server.sin6_port = htons(_port); | ||||
|  | ||||
|             if (ix::inet_pton(_addressFamily, _host.c_str(), &server.sin6_addr) <= 0) | ||||
|             if (inet_pton(_addressFamily, _host.c_str(), &server.sin6_addr) <= 0) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 ss << "SocketServer::listen() error calling inet_pton " | ||||
| @@ -338,7 +338,7 @@ namespace ix | ||||
|             if (_addressFamily == AF_INET) | ||||
|             { | ||||
|                 char remoteIp4[INET_ADDRSTRLEN]; | ||||
|                 if (ix::inet_ntop(AF_INET, &client.sin_addr, remoteIp4, INET_ADDRSTRLEN) == nullptr) | ||||
|                 if (inet_ntop(AF_INET, &client.sin_addr, remoteIp4, INET_ADDRSTRLEN) == nullptr) | ||||
|                 { | ||||
|                     int err = Socket::getErrno(); | ||||
|                     std::stringstream ss; | ||||
| @@ -357,8 +357,7 @@ namespace ix | ||||
|             else // AF_INET6 | ||||
|             { | ||||
|                 char remoteIp6[INET6_ADDRSTRLEN]; | ||||
|                 if (ix::inet_ntop(AF_INET6, &client.sin_addr, remoteIp6, INET6_ADDRSTRLEN) == | ||||
|                     nullptr) | ||||
|                 if (inet_ntop(AF_INET6, &client.sin_addr, remoteIp6, INET6_ADDRSTRLEN) == nullptr) | ||||
|                 { | ||||
|                     int err = Socket::getErrno(); | ||||
|                     std::stringstream ss; | ||||
|   | ||||
| @@ -14,7 +14,7 @@ namespace ix | ||||
|     bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char& c1, | ||||
|                                                         const unsigned char& c2) const | ||||
|     { | ||||
| #if defined(_WIN32) && !defined(__GNUC__) | ||||
| #ifdef _WIN32 | ||||
|         return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale()); | ||||
| #else | ||||
|         return std::tolower(c1) < std::tolower(c2); | ||||
|   | ||||
| @@ -15,12 +15,6 @@ | ||||
| #include <cmath> | ||||
|  | ||||
|  | ||||
| namespace | ||||
| { | ||||
|     const std::string emptyMsg; | ||||
| } // namespace | ||||
|  | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     OnTrafficTrackerCallback WebSocket::_onTrafficTrackerCallback = nullptr; | ||||
| @@ -28,14 +22,12 @@ namespace ix | ||||
|     const int WebSocket::kDefaultPingIntervalSecs(-1); | ||||
|     const bool WebSocket::kDefaultEnablePong(true); | ||||
|     const uint32_t WebSocket::kDefaultMaxWaitBetweenReconnectionRetries(10 * 1000); // 10s | ||||
|     const uint32_t WebSocket::kDefaultMinWaitBetweenReconnectionRetries(1);         // 1 ms | ||||
|  | ||||
|     WebSocket::WebSocket() | ||||
|         : _onMessageCallback(OnMessageCallback()) | ||||
|         , _stop(false) | ||||
|         , _automaticReconnection(true) | ||||
|         , _maxWaitBetweenReconnectionRetries(kDefaultMaxWaitBetweenReconnectionRetries) | ||||
|         , _minWaitBetweenReconnectionRetries(kDefaultMinWaitBetweenReconnectionRetries) | ||||
|         , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs) | ||||
|         , _enablePong(kDefaultEnablePong) | ||||
|         , _pingIntervalSecs(kDefaultPingIntervalSecs) | ||||
| @@ -44,7 +36,7 @@ namespace ix | ||||
|             [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) { | ||||
|                 _onMessageCallback( | ||||
|                     ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close, | ||||
|                                                       emptyMsg, | ||||
|                                                       "", | ||||
|                                                       wireSize, | ||||
|                                                       WebSocketErrorInfo(), | ||||
|                                                       WebSocketOpenInfo(), | ||||
| @@ -64,11 +56,6 @@ namespace ix | ||||
|         _url = url; | ||||
|     } | ||||
|  | ||||
|     void WebSocket::setHandshakeTimeout(int handshakeTimeoutSecs) | ||||
|     { | ||||
|         _handshakeTimeoutSecs = handshakeTimeoutSecs; | ||||
|     } | ||||
|  | ||||
|     void WebSocket::setExtraHeaders(const WebSocketHttpHeaders& headers) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
| @@ -144,24 +131,12 @@ namespace ix | ||||
|         _maxWaitBetweenReconnectionRetries = maxWaitBetweenReconnectionRetries; | ||||
|     } | ||||
|  | ||||
|     void WebSocket::setMinWaitBetweenReconnectionRetries(uint32_t minWaitBetweenReconnectionRetries) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
|         _minWaitBetweenReconnectionRetries = minWaitBetweenReconnectionRetries; | ||||
|     } | ||||
|  | ||||
|     uint32_t WebSocket::getMaxWaitBetweenReconnectionRetries() const | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
|         return _maxWaitBetweenReconnectionRetries; | ||||
|     } | ||||
|  | ||||
|     uint32_t WebSocket::getMinWaitBetweenReconnectionRetries() const | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
|         return _minWaitBetweenReconnectionRetries; | ||||
|     } | ||||
|  | ||||
|     void WebSocket::start() | ||||
|     { | ||||
|         if (_thread.joinable()) return; // we've already been started | ||||
| @@ -223,7 +198,7 @@ namespace ix | ||||
|  | ||||
|         _onMessageCallback(ix::make_unique<WebSocketMessage>( | ||||
|             WebSocketMessageType::Open, | ||||
|             emptyMsg, | ||||
|             "", | ||||
|             0, | ||||
|             WebSocketErrorInfo(), | ||||
|             WebSocketOpenInfo(status.uri, status.headers, status.protocol), | ||||
| @@ -238,9 +213,7 @@ namespace ix | ||||
|         return status; | ||||
|     } | ||||
|  | ||||
|     WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket, | ||||
|                                                    int timeoutSecs, | ||||
|                                                    bool enablePerMessageDeflate) | ||||
|     WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket, int timeoutSecs) | ||||
|     { | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lock(_configMutex); | ||||
| @@ -248,8 +221,7 @@ namespace ix | ||||
|                 _perMessageDeflateOptions, _socketTLSOptions, _enablePong, _pingIntervalSecs); | ||||
|         } | ||||
|  | ||||
|         WebSocketInitResult status = | ||||
|             _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate); | ||||
|         WebSocketInitResult status = _ws.connectToSocket(std::move(socket), timeoutSecs); | ||||
|         if (!status.success) | ||||
|         { | ||||
|             return status; | ||||
| @@ -257,7 +229,7 @@ namespace ix | ||||
|  | ||||
|         _onMessageCallback( | ||||
|             ix::make_unique<WebSocketMessage>(WebSocketMessageType::Open, | ||||
|                                               emptyMsg, | ||||
|                                               "", | ||||
|                                               0, | ||||
|                                               WebSocketErrorInfo(), | ||||
|                                               WebSocketOpenInfo(status.uri, status.headers), | ||||
| @@ -331,10 +303,8 @@ namespace ix | ||||
|  | ||||
|                 if (_automaticReconnection) | ||||
|                 { | ||||
|                     duration = | ||||
|                         millis(calculateRetryWaitMilliseconds(retries++, | ||||
|                                                               _maxWaitBetweenReconnectionRetries, | ||||
|                                                               _minWaitBetweenReconnectionRetries)); | ||||
|                     duration = millis(calculateRetryWaitMilliseconds( | ||||
|                         retries++, _maxWaitBetweenReconnectionRetries)); | ||||
|  | ||||
|                     connectErr.wait_time = duration.count(); | ||||
|                     connectErr.retries = retries; | ||||
| @@ -344,7 +314,7 @@ namespace ix | ||||
|                 connectErr.http_status = status.http_status; | ||||
|  | ||||
|                 _onMessageCallback(ix::make_unique<WebSocketMessage>(WebSocketMessageType::Error, | ||||
|                                                                      emptyMsg, | ||||
|                                                                      "", | ||||
|                                                                      0, | ||||
|                                                                      connectErr, | ||||
|                                                                      WebSocketOpenInfo(), | ||||
|   | ||||
| @@ -58,7 +58,6 @@ namespace ix | ||||
|         void enablePerMessageDeflate(); | ||||
|         void disablePerMessageDeflate(); | ||||
|         void addSubProtocol(const std::string& subProtocol); | ||||
|         void setHandshakeTimeout(int handshakeTimeoutSecs); | ||||
|  | ||||
|         // Run asynchronously, by calling start and stop. | ||||
|         void start(); | ||||
| @@ -101,9 +100,7 @@ namespace ix | ||||
|         void disableAutomaticReconnection(); | ||||
|         bool isAutomaticReconnectionEnabled() const; | ||||
|         void setMaxWaitBetweenReconnectionRetries(uint32_t maxWaitBetweenReconnectionRetries); | ||||
|         void setMinWaitBetweenReconnectionRetries(uint32_t minWaitBetweenReconnectionRetries); | ||||
|         uint32_t getMaxWaitBetweenReconnectionRetries() const; | ||||
|         uint32_t getMinWaitBetweenReconnectionRetries() const; | ||||
|         const std::vector<std::string>& getSubProtocols(); | ||||
|  | ||||
|     private: | ||||
| @@ -117,9 +114,7 @@ namespace ix | ||||
|         static void invokeTrafficTrackerCallback(size_t size, bool incoming); | ||||
|  | ||||
|         // Server | ||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, | ||||
|                                             int timeoutSecs, | ||||
|                                             bool enablePerMessageDeflate); | ||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, int timeoutSecs); | ||||
|  | ||||
|         WebSocketTransport _ws; | ||||
|  | ||||
| @@ -142,9 +137,7 @@ namespace ix | ||||
|         // Automatic reconnection | ||||
|         std::atomic<bool> _automaticReconnection; | ||||
|         static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries; | ||||
|         static const uint32_t kDefaultMinWaitBetweenReconnectionRetries; | ||||
|         uint32_t _maxWaitBetweenReconnectionRetries; | ||||
|         uint32_t _minWaitBetweenReconnectionRetries; | ||||
|  | ||||
|         // Make the sleeping in the automatic reconnection cancellable | ||||
|         std::mutex _sleepMutex; | ||||
|   | ||||
| @@ -204,9 +204,6 @@ namespace ix | ||||
|         // Check the value of the connection field | ||||
|         // Some websocket servers (Go/Gorilla?) send lowercase values for the | ||||
|         // connection header, so do a case insensitive comparison | ||||
|         // | ||||
|         // See https://github.com/apache/thrift/commit/7c4bdf9914fcba6c89e0f69ae48b9675578f084a | ||||
|         // | ||||
|         if (!insensitiveStringCompare(headers["connection"], "Upgrade")) | ||||
|         { | ||||
|             std::stringstream ss; | ||||
| @@ -244,8 +241,7 @@ namespace ix | ||||
|         return WebSocketInitResult(true, status, "", headers, path); | ||||
|     } | ||||
|  | ||||
|     WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs, | ||||
|                                                             bool enablePerMessageDeflate) | ||||
|     WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs) | ||||
|     { | ||||
|         _requestInitCancellation = false; | ||||
|  | ||||
| @@ -299,8 +295,7 @@ namespace ix | ||||
|             return sendErrorResponse(400, "Missing Upgrade header"); | ||||
|         } | ||||
|  | ||||
|         if (!insensitiveStringCompare(headers["upgrade"], "WebSocket") && | ||||
|             headers["Upgrade"] != "keep-alive, Upgrade") // special case for firefox | ||||
|         if (!insensitiveStringCompare(headers["upgrade"], "WebSocket")) | ||||
|         { | ||||
|             return sendErrorResponse(400, | ||||
|                                      "Invalid Upgrade header, " | ||||
| @@ -343,7 +338,7 @@ namespace ix | ||||
|         WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions(header); | ||||
|  | ||||
|         // If the client has requested that extension, | ||||
|         if (webSocketPerMessageDeflateOptions.enabled() && enablePerMessageDeflate) | ||||
|         if (webSocketPerMessageDeflateOptions.enabled()) | ||||
|         { | ||||
|             _enablePerMessageDeflate = true; | ||||
|  | ||||
|   | ||||
| @@ -35,7 +35,7 @@ namespace ix | ||||
|                                             int port, | ||||
|                                             int timeoutSecs); | ||||
|  | ||||
|         WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate); | ||||
|         WebSocketInitResult serverHandshake(int timeoutSecs); | ||||
|  | ||||
|     private: | ||||
|         std::string genRandomString(const int len); | ||||
|   | ||||
| @@ -42,18 +42,6 @@ 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>; | ||||
|   | ||||
| @@ -97,10 +97,9 @@ namespace ix | ||||
|         } | ||||
|         else if (_onClientMessageCallback) | ||||
|         { | ||||
|             WebSocket* webSocketRawPtr = webSocket.get(); | ||||
|             webSocket->setOnMessageCallback( | ||||
|                 [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) { | ||||
|                     _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); | ||||
|                 [this, &ws = *webSocket.get(), connectionState](const WebSocketMessagePtr& msg) { | ||||
|                     _onClientMessageCallback(connectionState, ws, msg); | ||||
|                 }); | ||||
|         } | ||||
|         else | ||||
| @@ -129,8 +128,7 @@ namespace ix | ||||
|             _clients.insert(webSocket); | ||||
|         } | ||||
|  | ||||
|         auto status = webSocket->connectToSocket( | ||||
|             std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate); | ||||
|         auto status = webSocket->connectToSocket(std::move(socket), _handshakeTimeoutSecs); | ||||
|         if (status.success) | ||||
|         { | ||||
|             // Process incoming messages and execute callbacks | ||||
| @@ -170,45 +168,4 @@ namespace ix | ||||
|         std::lock_guard<std::mutex> lock(_clientsMutex); | ||||
|         return _clients.size(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // Classic servers | ||||
|     // | ||||
|     void WebSocketServer::makeBroadcastServer() | ||||
|     { | ||||
|         setOnClientMessageCallback([this](std::shared_ptr<ConnectionState> connectionState, | ||||
|                                           WebSocket& webSocket, | ||||
|                                           const WebSocketMessagePtr& msg) { | ||||
|             auto remoteIp = connectionState->getRemoteIp(); | ||||
|             if (msg->type == ix::WebSocketMessageType::Message) | ||||
|             { | ||||
|                 for (auto&& client : getClients()) | ||||
|                 { | ||||
|                     if (client.get() != &webSocket) | ||||
|                     { | ||||
|                         client->send(msg->str, msg->binary); | ||||
|  | ||||
|                         // Make sure the OS send buffer is flushed before moving on | ||||
|                         do | ||||
|                         { | ||||
|                             std::chrono::duration<double, std::milli> duration(500); | ||||
|                             std::this_thread::sleep_for(duration); | ||||
|                         } while (client->bufferedAmount() != 0); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     bool WebSocketServer::listenAndStart() | ||||
|     { | ||||
|         auto res = listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         start(); | ||||
|         return true; | ||||
|     } | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -47,9 +47,6 @@ namespace ix | ||||
|         // Get all the connected clients | ||||
|         std::set<std::shared_ptr<WebSocket>> getClients(); | ||||
|  | ||||
|         void makeBroadcastServer(); | ||||
|         bool listenAndStart(); | ||||
|  | ||||
|         const static int kDefaultHandShakeTimeoutSecs; | ||||
|  | ||||
|     private: | ||||
|   | ||||
| @@ -169,8 +169,7 @@ namespace ix | ||||
|  | ||||
|     // Server | ||||
|     WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket, | ||||
|                                                             int timeoutSecs, | ||||
|                                                             bool enablePerMessageDeflate) | ||||
|                                                             int timeoutSecs) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_socketMutex); | ||||
|  | ||||
| @@ -187,7 +186,7 @@ namespace ix | ||||
|                                               _perMessageDeflateOptions, | ||||
|                                               _enablePerMessageDeflate); | ||||
|  | ||||
|         auto result = webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate); | ||||
|         auto result = webSocketHandshake.serverHandshake(timeoutSecs); | ||||
|         if (result.success) | ||||
|         { | ||||
|             setReadyState(ReadyState::OPEN); | ||||
|   | ||||
| @@ -83,9 +83,7 @@ namespace ix | ||||
|                                          int timeoutSecs); | ||||
|  | ||||
|         // Server | ||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, | ||||
|                                             int timeoutSecs, | ||||
|                                             bool enablePerMessageDeflate); | ||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, int timeoutSecs); | ||||
|  | ||||
|         PollResult poll(); | ||||
|         WebSocketSendInfo sendBinary(const std::string& message, | ||||
|   | ||||
| @@ -6,4 +6,4 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #define IX_WEBSOCKET_VERSION "11.2.8" | ||||
| #define IX_WEBSOCKET_VERSION "11.0.8" | ||||
|   | ||||
							
								
								
									
										27
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								main.cpp
									
									
									
									
									
								
							| @@ -9,13 +9,10 @@ | ||||
|  *  $ 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 | ||||
|  *  $ ./a.out | ||||
|  * | ||||
|  *  Or use cmake -DBUILD_DEMO=ON option for other platform | ||||
|  */ | ||||
|  | ||||
| #include <ixwebsocket/IXNetSystem.h> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <ixwebsocket/IXUserAgent.h> | ||||
| #include <iostream> | ||||
|  | ||||
| int main() | ||||
| @@ -26,12 +23,9 @@ int main() | ||||
|     // Our websocket object | ||||
|     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"); | ||||
|     webSocket.setUrl(url); | ||||
|  | ||||
|     std::cout << ix::userAgent() << std::endl; | ||||
|     std::cout << "Connecting to " << url << "..." << std::endl; | ||||
|  | ||||
|     // Setup a callback to be fired (in a background thread, watch out for race conditions !) | ||||
| @@ -41,18 +35,10 @@ int main() | ||||
|             if (msg->type == ix::WebSocketMessageType::Message) | ||||
|             { | ||||
|                 std::cout << "received message: " << msg->str << std::endl; | ||||
|                 std::cout << "> " << std::flush; | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Open) | ||||
|             { | ||||
|                 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; | ||||
|             } | ||||
|         } | ||||
|     ); | ||||
| @@ -63,16 +49,13 @@ int main() | ||||
|     // Send a message to the server (default to TEXT mode) | ||||
|     webSocket.send("hello world"); | ||||
|  | ||||
|     // Display a prompt | ||||
|     std::cout << "> " << std::flush; | ||||
|  | ||||
|     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)) | ||||
|     while (true) | ||||
|     { | ||||
|         webSocket.send(text); | ||||
|         std::string text; | ||||
|         std::cout << "> " << std::flush; | ||||
|         std::getline(std::cin, text); | ||||
|  | ||||
|         webSocket.send(text); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
|   | ||||
| @@ -113,7 +113,7 @@ test_server: | ||||
| test: | ||||
| 	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_TEST=1 ..) | ||||
| 	(cd build ; ninja) | ||||
| 	(cd build ; ninja -v test) | ||||
| 	(cd build ; ninja test) | ||||
|  | ||||
| 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") | ||||
|   | ||||
| @@ -33,7 +33,11 @@ TEST_CASE("dns", "[net]") | ||||
|         auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80); | ||||
|  | ||||
|         std::string errMsg; | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, | ||||
|                                                   [] | ||||
|                                                   { | ||||
|                                                       return false; | ||||
|                                                   }); | ||||
|         std::cerr << "Error message: " << errMsg << std::endl; | ||||
|         REQUIRE(res == nullptr); | ||||
|     } | ||||
| @@ -44,7 +48,11 @@ TEST_CASE("dns", "[net]") | ||||
|  | ||||
|         std::string errMsg; | ||||
|         // The callback returning true means we are requesting cancellation | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; }); | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, | ||||
|                                                   [] | ||||
|                                                   { | ||||
|                                                       return true; | ||||
|                                                   }); | ||||
|         std::cerr << "Error message: " << errMsg << std::endl; | ||||
|         REQUIRE(res == nullptr); | ||||
|     } | ||||
|   | ||||
| @@ -29,7 +29,6 @@ namespace ix | ||||
|  | ||||
|             // Comparison should be case insensitive | ||||
|             REQUIRE(httpHeaders["Foo"] == "foo"); | ||||
|             REQUIRE(httpHeaders["Foo"] != "bar"); | ||||
|         } | ||||
|  | ||||
|         SECTION("2") | ||||
| @@ -40,7 +39,7 @@ namespace ix | ||||
|  | ||||
|             headers["Upgrade"] = "webSocket"; | ||||
|  | ||||
|             REQUIRE(!CaseInsensitiveLess::cmp(headers["upGRADE"], "webSocket")); | ||||
|             REQUIRE(CaseInsensitiveLess::cmp(headers["upgrade"], "WebSocket") == 0); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -139,9 +139,8 @@ namespace ix | ||||
|         std::streamoff size = file.tellg(); | ||||
|         file.seekg(0, file.beg); | ||||
|  | ||||
|         memblock.reserve((size_t) size); | ||||
|         memblock.insert( | ||||
|             memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>()); | ||||
|         memblock.resize((size_t) size); | ||||
|         file.read((char*) &memblock.front(), static_cast<std::streamsize>(size)); | ||||
|  | ||||
|         return memblock; | ||||
|     } | ||||
|   | ||||
							
								
								
									
										5
									
								
								third_party/cpp-linenoise/linenoise.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								third_party/cpp-linenoise/linenoise.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1639,10 +1639,7 @@ bool enableRawMode(int fd) { | ||||
|  | ||||
|         /* Init windows console handles only once */ | ||||
|         hOut = GetStdHandle(STD_OUTPUT_HANDLE); | ||||
|         if (hOut==INVALID_HANDLE_VALUE) { | ||||
|             errno = ENOTTY; | ||||
|             return false; | ||||
|         } | ||||
|         if (hOut==INVALID_HANDLE_VALUE) goto fatal; | ||||
|     } | ||||
|  | ||||
|     DWORD consolemodeOut; | ||||
|   | ||||
							
								
								
									
										166
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										166
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -55,17 +55,16 @@ namespace | ||||
|     std::pair<bool, std::vector<uint8_t>> load(const std::string& path) | ||||
|     { | ||||
|         std::vector<uint8_t> memblock; | ||||
|         std::ifstream file(path); | ||||
|  | ||||
|         std::ifstream file(path); | ||||
|         if (!file.is_open()) return std::make_pair(false, memblock); | ||||
|  | ||||
|         file.seekg(0, file.end); | ||||
|         std::streamoff size = file.tellg(); | ||||
|         file.seekg(0, file.beg); | ||||
|  | ||||
|         memblock.reserve((size_t) size); | ||||
|         memblock.insert( | ||||
|             memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>()); | ||||
|         memblock.resize((size_t) size); | ||||
|         file.read((char*) &memblock.front(), static_cast<std::streamsize>(size)); | ||||
|  | ||||
|         return std::make_pair(true, memblock); | ||||
|     } | ||||
| @@ -87,9 +86,9 @@ namespace | ||||
|         std::streamoff size = file.tellg(); | ||||
|         file.seekg(0, file.beg); | ||||
|  | ||||
|         memblock.reserve((size_t) size); | ||||
|         memblock.insert( | ||||
|             memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>()); | ||||
|         memblock.resize(size); | ||||
|  | ||||
|         file.read((char*) &memblock.front(), static_cast<std::streamsize>(size)); | ||||
|  | ||||
|         std::string bytes(memblock.begin(), memblock.end()); | ||||
|         return bytes; | ||||
| @@ -440,6 +439,93 @@ namespace ix | ||||
|         return generateReport(url) ? 0 : 1; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     //  broadcast server | ||||
|     // | ||||
|     int ws_broadcast_server_main(int port, | ||||
|                                  const std::string& hostname, | ||||
|                                  const ix::SocketTLSOptions& tlsOptions) | ||||
|     { | ||||
|         spdlog::info("Listening on {}:{}", hostname, port); | ||||
|  | ||||
|         ix::WebSocketServer server(port, hostname); | ||||
|         server.setTLSOptions(tlsOptions); | ||||
|  | ||||
|         server.setOnClientMessageCallback( | ||||
|             [&server](std::shared_ptr<ConnectionState> connectionState, | ||||
|                       WebSocket& webSocket, | ||||
|                       const WebSocketMessagePtr& msg) { | ||||
|                 auto remoteIp = connectionState->getRemoteIp(); | ||||
|                 if (msg->type == ix::WebSocketMessageType::Open) | ||||
|                 { | ||||
|                     spdlog::info("New connection"); | ||||
|                     spdlog::info("remote ip: {}", remoteIp); | ||||
|                     spdlog::info("id: {}", connectionState->getId()); | ||||
|                     spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                     spdlog::info("Headers:"); | ||||
|                     for (auto it : msg->openInfo.headers) | ||||
|                     { | ||||
|                         spdlog::info("{}: {}", it.first, it.second); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                 { | ||||
|                     spdlog::info("Closed connection: code {} reason {}", | ||||
|                                  msg->closeInfo.code, | ||||
|                                  msg->closeInfo.reason); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                 { | ||||
|                     std::stringstream ss; | ||||
|                     ss << "Connection error: " << msg->errorInfo.reason << std::endl; | ||||
|                     ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                     ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                     ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                     spdlog::info(ss.str()); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Fragment) | ||||
|                 { | ||||
|                     spdlog::info("Received message fragment"); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                 { | ||||
|                     spdlog::info("Received {} bytes", msg->wireSize); | ||||
|  | ||||
|                     for (auto&& client : server.getClients()) | ||||
|                     { | ||||
|                         if (client.get() != &webSocket) | ||||
|                         { | ||||
|                             client->send(msg->str, msg->binary, [](int current, int total) -> bool { | ||||
|                                 spdlog::info("Step {} out of {}", current, total); | ||||
|                                 return true; | ||||
|                             }); | ||||
|  | ||||
|                             do | ||||
|                             { | ||||
|                                 size_t bufferedAmount = client->bufferedAmount(); | ||||
|                                 spdlog::info("{} bytes left to be sent", bufferedAmount); | ||||
|  | ||||
|                                 std::chrono::duration<double, std::milli> duration(500); | ||||
|                                 std::this_thread::sleep_for(duration); | ||||
|                             } while (client->bufferedAmount() != 0); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::info(res.second); | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         server.start(); | ||||
|         server.wait(); | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      *  ws_chat.cpp | ||||
|      *  Author: Benjamin Sergeant | ||||
| @@ -902,11 +988,8 @@ namespace ix | ||||
|  | ||||
|         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]; | ||||
|         ix::inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN); | ||||
|         inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN); | ||||
|  | ||||
|         spdlog::info("host: {} ip: {}", hostname, str); | ||||
|  | ||||
| @@ -1425,18 +1508,10 @@ namespace ix | ||||
|                     filename = output; | ||||
|                 } | ||||
|  | ||||
|                 if (filename.empty()) | ||||
|                 { | ||||
|                     spdlog::error("Cannot save content to disk: No output file supplied, and not " | ||||
|                                   "filename could be extracted from the url {}", | ||||
|                                   url); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                 spdlog::info("Writing to disk: {}", filename); | ||||
|                 std::ofstream out(filename); | ||||
|                     out << response->body; | ||||
|                 } | ||||
|                 out.write((char*) &response->body.front(), response->body.size()); | ||||
|                 out.close(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| @@ -1893,8 +1968,7 @@ namespace ix | ||||
|  | ||||
|         spdlog::info("ws_receive: Writing to disk: {}", filenameTmp); | ||||
|         std::ofstream out(filenameTmp); | ||||
|         std::string contentAsString(content.begin(), content.end()); | ||||
|         out << contentAsString; | ||||
|         out.write((char*) &content.front(), content.size()); | ||||
|         out.close(); | ||||
|  | ||||
|         spdlog::info("ws_receive: Renaming {} to {}", filenameTmp, filename); | ||||
| @@ -2082,6 +2156,23 @@ namespace ix | ||||
|         _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() | ||||
|     { | ||||
|         _webSocket.setUrl(_url); | ||||
| @@ -2175,8 +2266,7 @@ namespace ix | ||||
|         std::vector<uint8_t> content; | ||||
|         { | ||||
|             Bench bench("ws_send: load file from disk"); | ||||
|             auto res = load(filename); | ||||
|             content = res.second; | ||||
|             content = load(filename); | ||||
|         } | ||||
|  | ||||
|         _id = uuid4(); | ||||
| @@ -2372,9 +2462,9 @@ namespace ix | ||||
|                             else | ||||
|                             { | ||||
|                                 std::string readyStateString = | ||||
|                                     readyState == ReadyState::Connecting ? "Connecting" | ||||
|                                     : readyState == ReadyState::Closing  ? "Closing" | ||||
|                                                                          : "Closed"; | ||||
|                                     readyState == ReadyState::Connecting | ||||
|                                         ? "Connecting" | ||||
|                                         : readyState == ReadyState::Closing ? "Closing" : "Closed"; | ||||
|                                 size_t bufferedAmount = client->bufferedAmount(); | ||||
|  | ||||
|                                 spdlog::info( | ||||
| @@ -2487,7 +2577,7 @@ int main(int argc, char** argv) | ||||
|     int delayMs = -1; | ||||
|     int count = 1; | ||||
|     int msgCount = 1000 * 1000; | ||||
|     uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds | ||||
|     uint32_t maxWaitBetweenReconnectionRetries; | ||||
|     int pingIntervalSecs = 30; | ||||
|     int runCount = 1; | ||||
|  | ||||
| @@ -2763,19 +2853,9 @@ int main(int argc, char** argv) | ||||
|         ret = ix::ws_push_server( | ||||
|             port, hostname, tlsOptions, ipv6, disablePerMessageDeflate, disablePong, sendMsg); | ||||
|     } | ||||
|     else if (app.got_subcommand("transfer") || app.got_subcommand("broadcast_server")) | ||||
|     else if (app.got_subcommand("transfer")) | ||||
|     { | ||||
|         ix::WebSocketServer server(port, hostname); | ||||
|         server.setTLSOptions(tlsOptions); | ||||
|         server.makeBroadcastServer(); | ||||
|         if (!server.listenAndStart()) | ||||
|         { | ||||
|             spdlog::error("Error while starting the server"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             server.wait(); | ||||
|         } | ||||
|         ret = ix::ws_transfer_main(port, hostname, tlsOptions); | ||||
|     } | ||||
|     else if (app.got_subcommand("send")) | ||||
|     { | ||||
| @@ -2790,6 +2870,10 @@ int main(int argc, char** argv) | ||||
|     { | ||||
|         ret = ix::ws_chat_main(url, user); | ||||
|     } | ||||
|     else if (app.got_subcommand("broadcast_server")) | ||||
|     { | ||||
|         ret = ix::ws_broadcast_server_main(port, hostname, tlsOptions); | ||||
|     } | ||||
|     else if (app.got_subcommand("ping")) | ||||
|     { | ||||
|         ret = ix::ws_ping_pong_main(url, tlsOptions); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user