Compare commits
	
		
			1 Commits
		
	
	
		
			v11.4.4
			...
			revert-370
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b1a72f6133 | 
							
								
								
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | name: Mark stale issues and pull requests | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   schedule: | ||||||
|  |   - cron: "0 0 * * *" | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   stale: | ||||||
|  |  | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/stale@v1 | ||||||
|  |       with: | ||||||
|  |         repo-token: ${{ secrets.GITHUB_TOKEN }} | ||||||
|  |         stale-issue-message: 'Stale issue message' | ||||||
|  |         stale-pr-message: 'Stale pull request message' | ||||||
|  |         stale-issue-label: 'no-issue-activity' | ||||||
|  |         stale-pr-label: 'no-pr-activity' | ||||||
| @@ -6,12 +6,11 @@ | |||||||
| cmake_minimum_required(VERSION 3.4.1...3.17.2) | cmake_minimum_required(VERSION 3.4.1...3.17.2) | ||||||
| set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") | ||||||
|  |  | ||||||
| project(ixwebsocket LANGUAGES C CXX VERSION 11.4.4) | project(ixwebsocket C CXX) | ||||||
|  |  | ||||||
| set (CMAKE_CXX_STANDARD 11) | 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) | ||||||
| set (CMAKE_EXPORT_COMPILE_COMMANDS yes) |  | ||||||
|  |  | ||||||
| option (BUILD_DEMO OFF) | option (BUILD_DEMO OFF) | ||||||
|  |  | ||||||
| @@ -67,7 +66,6 @@ set( IXWEBSOCKET_SOURCES | |||||||
| ) | ) | ||||||
|  |  | ||||||
| set( IXWEBSOCKET_HEADERS | set( IXWEBSOCKET_HEADERS | ||||||
|     ixwebsocket/IXBase64.h |  | ||||||
|     ixwebsocket/IXBench.h |     ixwebsocket/IXBench.h | ||||||
|     ixwebsocket/IXCancellationRequest.h |     ixwebsocket/IXCancellationRequest.h | ||||||
|     ixwebsocket/IXConnectionState.h |     ixwebsocket/IXConnectionState.h | ||||||
| @@ -136,7 +134,6 @@ if (USE_TLS) | |||||||
|     else() # default to OpenSSL on all other platforms |     else() # default to OpenSSL on all other platforms | ||||||
|       if (NOT USE_MBED_TLS) # Unless mbedtls is requested |       if (NOT USE_MBED_TLS) # Unless mbedtls is requested | ||||||
|         set(USE_OPEN_SSL ON) |         set(USE_OPEN_SSL ON) | ||||||
|         set(requires "openssl") |  | ||||||
|       endif() |       endif() | ||||||
|     endif() |     endif() | ||||||
|  |  | ||||||
| @@ -166,9 +163,9 @@ if(BUILD_SHARED_LIBS) | |||||||
|         ${IXWEBSOCKET_SOURCES} |         ${IXWEBSOCKET_SOURCES} | ||||||
|         ${IXWEBSOCKET_HEADERS} |         ${IXWEBSOCKET_HEADERS} | ||||||
|     ) |     ) | ||||||
|  |      | ||||||
|     # Set library version |     # Set library version | ||||||
|     set_target_properties(ixwebsocket PROPERTIES VERSION ${CMAKE_PROJECT_VERSION}) |     set_target_properties(ixwebsocket PROPERTIES VERSION 11.3.2) | ||||||
|  |  | ||||||
| else() | else() | ||||||
|     # Static library |     # Static library | ||||||
| @@ -237,7 +234,11 @@ endif() | |||||||
| option(USE_ZLIB "Enable zlib support" TRUE) | option(USE_ZLIB "Enable zlib support" TRUE) | ||||||
|  |  | ||||||
| if (USE_ZLIB) | if (USE_ZLIB) | ||||||
|   find_package(ZLIB REQUIRED) |   # This ZLIB_FOUND check is to help find a cmake manually configured zlib | ||||||
|  |   if (NOT ZLIB_FOUND) | ||||||
|  |     find_package(ZLIB REQUIRED) | ||||||
|  |   endif() | ||||||
|  |   target_include_directories(ixwebsocket PUBLIC $<BUILD_INTERFACE:${ZLIB_INCLUDE_DIRS}>) | ||||||
|   target_link_libraries(ixwebsocket PRIVATE ZLIB::ZLIB) |   target_link_libraries(ixwebsocket PRIVATE ZLIB::ZLIB) | ||||||
|  |  | ||||||
|   target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_ZLIB) |   target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_ZLIB) | ||||||
| @@ -252,7 +253,7 @@ if (WIN32) | |||||||
|   endif() |   endif() | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if (UNIX AND NOT APPLE) | if (UNIX) | ||||||
|   set(THREADS_PREFER_PTHREAD_FLAG TRUE) |   set(THREADS_PREFER_PTHREAD_FLAG TRUE) | ||||||
|   find_package(Threads) |   find_package(Threads) | ||||||
|   target_link_libraries(ixwebsocket PRIVATE Threads::Threads) |   target_link_libraries(ixwebsocket PRIVATE Threads::Threads) | ||||||
| @@ -288,18 +289,10 @@ if (IXWEBSOCKET_INSTALL) | |||||||
|           PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ixwebsocket/ |           PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ixwebsocket/ | ||||||
|   ) |   ) | ||||||
|  |  | ||||||
|   configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-config.cmake" @ONLY) |  | ||||||
|   install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket") |  | ||||||
|    |  | ||||||
|   set(prefix ${CMAKE_INSTALL_PREFIX}) |  | ||||||
|   configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket.pc" @ONLY) |  | ||||||
|   install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") |  | ||||||
|  |  | ||||||
|   install(EXPORT ixwebsocket |   install(EXPORT ixwebsocket | ||||||
|           FILE ixwebsocket-targets.cmake |           FILE ixwebsocket-config.cmake | ||||||
|           NAMESPACE ixwebsocket:: |           NAMESPACE ixwebsocket:: | ||||||
|           DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket |           DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket) | ||||||
|   ) |  | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if (USE_WS OR USE_TEST) | if (USE_WS OR USE_TEST) | ||||||
|   | |||||||
| @@ -35,7 +35,6 @@ int main() | |||||||
|  |  | ||||||
|     // Connect to a server with encryption |     // Connect to a server with encryption | ||||||
|     // See https://machinezone.github.io/IXWebSocket/usage/#tls-support-and-configuration |     // See https://machinezone.github.io/IXWebSocket/usage/#tls-support-and-configuration | ||||||
|     //     https://github.com/machinezone/IXWebSocket/issues/386#issuecomment-1105235227 (self signed certificates) |  | ||||||
|     std::string url("wss://echo.websocket.org"); |     std::string url("wss://echo.websocket.org"); | ||||||
|     webSocket.setUrl(url); |     webSocket.setUrl(url); | ||||||
|  |  | ||||||
| @@ -107,7 +106,6 @@ If your company or project is using this library, feel free to open an issue or | |||||||
| - [Teleport](http://teleportconnect.com/), Teleport is your own personal remote robot avatar | - [Teleport](http://teleportconnect.com/), Teleport is your own personal remote robot avatar | ||||||
| - [Abaddon](https://github.com/uowuo/abaddon), An alternative Discord client made with C++/gtkmm  | - [Abaddon](https://github.com/uowuo/abaddon), An alternative Discord client made with C++/gtkmm  | ||||||
| - [NovaCoin](https://github.com/novacoin-project/novacoin), a hybrid scrypt PoW + PoS based cryptocurrency. | - [NovaCoin](https://github.com/novacoin-project/novacoin), a hybrid scrypt PoW + PoS based cryptocurrency. | ||||||
| - [Candy](https://github.com/lanthora/candy), A WebSocket and TUN based VPN for Linux  |  | ||||||
|  |  | ||||||
| ## Alternative libraries | ## Alternative libraries | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,18 +2,6 @@ | |||||||
|  |  | ||||||
| All changes to this project will be documented in this file. | All changes to this project will be documented in this file. | ||||||
|  |  | ||||||
| ## [11.4.4] - 2023-06-05 |  | ||||||
|  |  | ||||||
| ## [11.4.3] - 2022-05-13 |  | ||||||
|  |  | ||||||
| Set shorter thread names |  | ||||||
| BoringSSL fix with SNI |  | ||||||
| Websocket computed header is valid Base64 |  | ||||||
|  |  | ||||||
| ## [11.4.1] - 2022-04-23 |  | ||||||
|  |  | ||||||
| vckpg + cmake fix, to handle zlib as a dependency better |  | ||||||
|  |  | ||||||
| ## [11.4.0] - 2022-01-05 | ## [11.4.0] - 2022-01-05 | ||||||
|  |  | ||||||
| (Windows) Use wsa select event, which should lead to a much better behavior on Windows in general, and also when sending large payloads (#342) | (Windows) Use wsa select event, which should lead to a much better behavior on Windows in general, and also when sending large payloads (#342) | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ To use the installed package within a cmake project, use the following: | |||||||
|  # include headers |  # include headers | ||||||
|  include_directories(${IXWEBSOCKET_INCLUDE_DIR}) |  include_directories(${IXWEBSOCKET_INCLUDE_DIR}) | ||||||
|  # ... |  # ... | ||||||
|  target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUND |  target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUNS | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|   | |||||||
| @@ -301,9 +301,7 @@ This api was actually changed to take a weak_ptr<WebSocket> as the first argumen | |||||||
|  |  | ||||||
| // Run a server on localhost at a given port. | // Run a server on localhost at a given port. | ||||||
| // 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. | ||||||
| int port = 8008; | ix::WebSocketServer server(port); | ||||||
| std::string host("127.0.0.1"); // If you need this server to be accessible on a different machine, use "0.0.0.0" |  | ||||||
| ix::WebSocketServer server(port, host); |  | ||||||
|  |  | ||||||
| server.setOnConnectionCallback( | server.setOnConnectionCallback( | ||||||
|     [&server](std::weak_ptr<WebSocket> webSocket, |     [&server](std::weak_ptr<WebSocket> webSocket, | ||||||
| @@ -386,9 +384,7 @@ The webSocket reference is guaranteed to be always valid ; by design the callbac | |||||||
|  |  | ||||||
| // Run a server on localhost at a given port. | // Run a server on localhost at a given port. | ||||||
| // 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. | ||||||
| int port = 8008; | ix::WebSocketServer server(port); | ||||||
| std::string host("127.0.0.1"); // If you need this server to be accessible on a different machine, use "0.0.0.0" |  | ||||||
| ix::WebSocketServer server(port, host); |  | ||||||
|  |  | ||||||
| server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) { | server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) { | ||||||
|     // The ConnectionState object contains information about the connection, |     // The ConnectionState object contains information about the connection, | ||||||
| @@ -628,5 +624,3 @@ For a client, specifying `caFile` can be used if connecting to a server that use | |||||||
| For a server, specifying `caFile` implies that: | For a server, specifying `caFile` implies that: | ||||||
| 1. You require clients to present a certificate | 1. You require clients to present a certificate | ||||||
| 1. It must be signed by one of the trusted roots in the file | 1. It must be signed by one of the trusted roots in the file | ||||||
|  |  | ||||||
| By default, a destination's hostname is always validated against the certificate that it presents. To accept certificates with any hostname, set `ix::SocketTLSOptions::disable_hostname_validation` to `true`. |  | ||||||
|   | |||||||
| @@ -1,9 +0,0 @@ | |||||||
| @PACKAGE_INIT@ |  | ||||||
|  |  | ||||||
| include(CMakeFindDependencyMacro) |  | ||||||
|  |  | ||||||
| if (@USE_ZLIB@) |  | ||||||
|   find_dependency(ZLIB) |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| include("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-targets.cmake") |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| prefix=@prefix@ |  | ||||||
| exec_prefix=${prefix} |  | ||||||
| libdir=${exec_prefix}/lib |  | ||||||
| includedir=${prefix}/include |  | ||||||
|  |  | ||||||
| Name: ixwebsocket |  | ||||||
| Description: websocket and http client and server library, with TLS support and very few dependencies |  | ||||||
| Version: @CMAKE_PROJECT_VERSION@ |  | ||||||
| Libs: -L${libdir} -lixwebsocket |  | ||||||
| Cflags: -I${includedir} |  | ||||||
| Requires: @requires@ |  | ||||||
| @@ -1,125 +0,0 @@ | |||||||
| #ifndef _MACARON_BASE64_H_ |  | ||||||
| #define _MACARON_BASE64_H_ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * The MIT License (MIT) |  | ||||||
|  * Copyright (c) 2016 tomykaira |  | ||||||
|  * |  | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining |  | ||||||
|  * a copy of this software and associated documentation files (the |  | ||||||
|  * "Software"), to deal in the Software without restriction, including |  | ||||||
|  * without limitation the rights to use, copy, modify, merge, publish, |  | ||||||
|  * distribute, sublicense, and/or sell copies of the Software, and to |  | ||||||
|  * permit persons to whom the Software is furnished to do so, subject to |  | ||||||
|  * the following conditions: |  | ||||||
|  * |  | ||||||
|  * The above copyright notice and this permission notice shall be |  | ||||||
|  * included in all copies or substantial portions of the Software. |  | ||||||
|  * |  | ||||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |  | ||||||
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |  | ||||||
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |  | ||||||
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |  | ||||||
|  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |  | ||||||
|  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |  | ||||||
|  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| namespace macaron { |  | ||||||
|  |  | ||||||
| class Base64 { |  | ||||||
|  public: |  | ||||||
|  |  | ||||||
|   static std::string Encode(const std::string data) { |  | ||||||
|     static constexpr char sEncodingTable[] = { |  | ||||||
|       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', |  | ||||||
|       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', |  | ||||||
|       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', |  | ||||||
|       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', |  | ||||||
|       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', |  | ||||||
|       'o', 'p', 'q', 'r', 's', 't', 'u', 'v', |  | ||||||
|       'w', 'x', 'y', 'z', '0', '1', '2', '3', |  | ||||||
|       '4', '5', '6', '7', '8', '9', '+', '/' |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     size_t in_len = data.size(); |  | ||||||
|     size_t out_len = 4 * ((in_len + 2) / 3); |  | ||||||
|     std::string ret(out_len, '\0'); |  | ||||||
|     size_t i; |  | ||||||
|     char *p = const_cast<char*>(ret.c_str()); |  | ||||||
|  |  | ||||||
|     for (i = 0; i < in_len - 2; i += 3) { |  | ||||||
|       *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; |  | ||||||
|       *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; |  | ||||||
|       *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; |  | ||||||
|       *p++ = sEncodingTable[data[i + 2] & 0x3F]; |  | ||||||
|     } |  | ||||||
|     if (i < in_len) { |  | ||||||
|       *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; |  | ||||||
|       if (i == (in_len - 1)) { |  | ||||||
|         *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; |  | ||||||
|         *p++ = '='; |  | ||||||
|       } |  | ||||||
|       else { |  | ||||||
|         *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; |  | ||||||
|         *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; |  | ||||||
|       } |  | ||||||
|       *p++ = '='; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return ret; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   static std::string Decode(const std::string& input, std::string& out) { |  | ||||||
|     static constexpr unsigned char kDecodingTable[] = { |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, |  | ||||||
|       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, |  | ||||||
|       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, |  | ||||||
|       64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |  | ||||||
|       41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, |  | ||||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     size_t in_len = input.size(); |  | ||||||
|     if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; |  | ||||||
|  |  | ||||||
|     size_t out_len = in_len / 4 * 3; |  | ||||||
|     if (input[in_len - 1] == '=') out_len--; |  | ||||||
|     if (input[in_len - 2] == '=') out_len--; |  | ||||||
|  |  | ||||||
|     out.resize(out_len); |  | ||||||
|  |  | ||||||
|     for (size_t i = 0, j = 0; i < in_len;) { |  | ||||||
|       uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |  | ||||||
|       uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |  | ||||||
|       uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |  | ||||||
|       uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; |  | ||||||
|  |  | ||||||
|       uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); |  | ||||||
|  |  | ||||||
|       if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; |  | ||||||
|       if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; |  | ||||||
|       if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return ""; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif /* _MACARON_BASE64_H_ */ |  | ||||||
| @@ -6,7 +6,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <cstdint> | #include <stdint.h> | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
|   | |||||||
| @@ -7,9 +7,9 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstdint> |  | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <stdint.h> | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
|   | |||||||
| @@ -23,7 +23,6 @@ | |||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <utility> |  | ||||||
|  |  | ||||||
| // mingw build quirks | // mingw build quirks | ||||||
| #if defined(_WIN32) && defined(__GNUC__) | #if defined(_WIN32) && defined(__GNUC__) | ||||||
| @@ -45,7 +44,7 @@ namespace ix | |||||||
|         ; |         ; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DNSLookup::AddrInfoPtr DNSLookup::getAddrInfo(const std::string& hostname, |     struct addrinfo* DNSLookup::getAddrInfo(const std::string& hostname, | ||||||
|                                             int port, |                                             int port, | ||||||
|                                             std::string& errMsg) |                                             std::string& errMsg) | ||||||
|     { |     { | ||||||
| @@ -64,10 +63,10 @@ namespace ix | |||||||
|             errMsg = gai_strerror(getaddrinfo_result); |             errMsg = gai_strerror(getaddrinfo_result); | ||||||
|             res = nullptr; |             res = nullptr; | ||||||
|         } |         } | ||||||
|         return AddrInfoPtr{ res, freeaddrinfo }; |         return res; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DNSLookup::AddrInfoPtr DNSLookup::resolve(std::string& errMsg, |     struct addrinfo* DNSLookup::resolve(std::string& errMsg, | ||||||
|                                         const CancellationRequest& isCancellationRequested, |                                         const CancellationRequest& isCancellationRequested, | ||||||
|                                         bool cancellable) |                                         bool cancellable) | ||||||
|     { |     { | ||||||
| @@ -75,7 +74,12 @@ namespace ix | |||||||
|                            : resolveUnCancellable(errMsg, isCancellationRequested); |                            : resolveUnCancellable(errMsg, isCancellationRequested); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DNSLookup::AddrInfoPtr DNSLookup::resolveUnCancellable( |     void DNSLookup::release(struct addrinfo* addr) | ||||||
|  |     { | ||||||
|  |         freeaddrinfo(addr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     struct addrinfo* DNSLookup::resolveUnCancellable( | ||||||
|         std::string& errMsg, const CancellationRequest& isCancellationRequested) |         std::string& errMsg, const CancellationRequest& isCancellationRequested) | ||||||
|     { |     { | ||||||
|         errMsg = "no error"; |         errMsg = "no error"; | ||||||
| @@ -90,7 +94,7 @@ namespace ix | |||||||
|         return getAddrInfo(_hostname, _port, errMsg); |         return getAddrInfo(_hostname, _port, errMsg); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DNSLookup::AddrInfoPtr DNSLookup::resolveCancellable( |     struct addrinfo* DNSLookup::resolveCancellable( | ||||||
|         std::string& errMsg, const CancellationRequest& isCancellationRequested) |         std::string& errMsg, const CancellationRequest& isCancellationRequested) | ||||||
|     { |     { | ||||||
|         errMsg = "no error"; |         errMsg = "no error"; | ||||||
| @@ -153,7 +157,7 @@ namespace ix | |||||||
|         // gone, so we use temporary variables (res) or we pass in by copy everything that |         // gone, so we use temporary variables (res) or we pass in by copy everything that | ||||||
|         // getAddrInfo needs to work. |         // getAddrInfo needs to work. | ||||||
|         std::string errMsg; |         std::string errMsg; | ||||||
|         auto res = getAddrInfo(hostname, port, errMsg); |         struct addrinfo* res = getAddrInfo(hostname, port, errMsg); | ||||||
|  |  | ||||||
|         if (auto lock = self.lock()) |         if (auto lock = self.lock()) | ||||||
|         { |         { | ||||||
| @@ -177,13 +181,13 @@ namespace ix | |||||||
|         return _errMsg; |         return _errMsg; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void DNSLookup::setRes(DNSLookup::AddrInfoPtr addr) |     void DNSLookup::setRes(struct addrinfo* addr) | ||||||
|     { |     { | ||||||
|         std::lock_guard<std::mutex> lock(_resMutex); |         std::lock_guard<std::mutex> lock(_resMutex); | ||||||
|         _res = std::move(addr); |         _res = addr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DNSLookup::AddrInfoPtr DNSLookup::getRes() |     struct addrinfo* DNSLookup::getRes() | ||||||
|     { |     { | ||||||
|         std::lock_guard<std::mutex> lock(_resMutex); |         std::lock_guard<std::mutex> lock(_resMutex); | ||||||
|         return _res; |         return _res; | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ | |||||||
|  |  | ||||||
| #include "IXCancellationRequest.h" | #include "IXCancellationRequest.h" | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstdint> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include <set> | #include <set> | ||||||
| @@ -25,21 +24,22 @@ namespace ix | |||||||
|     class DNSLookup : public std::enable_shared_from_this<DNSLookup> |     class DNSLookup : public std::enable_shared_from_this<DNSLookup> | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         using AddrInfoPtr = std::shared_ptr<addrinfo>; |  | ||||||
|         DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait); |         DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait); | ||||||
|         ~DNSLookup() = default; |         ~DNSLookup() = default; | ||||||
|  |  | ||||||
|         AddrInfoPtr resolve(std::string& errMsg, |         struct addrinfo* resolve(std::string& errMsg, | ||||||
|                                  const CancellationRequest& isCancellationRequested, |                                  const CancellationRequest& isCancellationRequested, | ||||||
|                                  bool cancellable = true); |                                  bool cancellable = true); | ||||||
|  |  | ||||||
|  |         void release(struct addrinfo* addr); | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         AddrInfoPtr resolveCancellable(std::string& errMsg, |         struct addrinfo* resolveCancellable(std::string& errMsg, | ||||||
|                                             const CancellationRequest& isCancellationRequested); |                                             const CancellationRequest& isCancellationRequested); | ||||||
|         AddrInfoPtr resolveUnCancellable(std::string& errMsg, |         struct addrinfo* resolveUnCancellable(std::string& errMsg, | ||||||
|                                               const CancellationRequest& isCancellationRequested); |                                               const CancellationRequest& isCancellationRequested); | ||||||
|  |  | ||||||
|         AddrInfoPtr getAddrInfo(const std::string& hostname, |         static struct addrinfo* getAddrInfo(const std::string& hostname, | ||||||
|                                             int port, |                                             int port, | ||||||
|                                             std::string& errMsg); |                                             std::string& errMsg); | ||||||
|  |  | ||||||
| @@ -48,15 +48,15 @@ namespace ix | |||||||
|         void setErrMsg(const std::string& errMsg); |         void setErrMsg(const std::string& errMsg); | ||||||
|         const std::string& getErrMsg(); |         const std::string& getErrMsg(); | ||||||
|  |  | ||||||
|         void setRes(AddrInfoPtr addr); |         void setRes(struct addrinfo* addr); | ||||||
|         AddrInfoPtr getRes(); |         struct addrinfo* getRes(); | ||||||
|  |  | ||||||
|         std::string _hostname; |         std::string _hostname; | ||||||
|         int _port; |         int _port; | ||||||
|         int64_t _wait; |         int64_t _wait; | ||||||
|         const static int64_t kDefaultWait; |         const static int64_t kDefaultWait; | ||||||
|  |  | ||||||
|         AddrInfoPtr _res; |         struct addrinfo* _res; | ||||||
|         std::mutex _resMutex; |         std::mutex _resMutex; | ||||||
|  |  | ||||||
|         std::string _errMsg; |         std::string _errMsg; | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ | |||||||
| #include "IXProgressCallback.h" | #include "IXProgressCallback.h" | ||||||
| #include "IXWebSocketHttpHeaders.h" | #include "IXWebSocketHttpHeaders.h" | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstdint> |  | ||||||
| #include <tuple> | #include <tuple> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ | |||||||
| #include "IXUserAgent.h" | #include "IXUserAgent.h" | ||||||
| #include "IXWebSocketHttpHeaders.h" | #include "IXWebSocketHttpHeaders.h" | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <cstdint> |  | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
| #include <random> | #include <random> | ||||||
| @@ -140,9 +139,8 @@ namespace ix | |||||||
|  |  | ||||||
|         std::string protocol, host, path, query; |         std::string protocol, host, path, query; | ||||||
|         int port; |         int port; | ||||||
|         bool isProtocolDefaultPort; |  | ||||||
|  |  | ||||||
|         if (!UrlParser::parse(url, protocol, host, path, query, port, isProtocolDefaultPort)) |         if (!UrlParser::parse(url, protocol, host, path, query, port)) | ||||||
|         { |         { | ||||||
|             std::stringstream ss; |             std::stringstream ss; | ||||||
|             ss << "Cannot parse url: " << url; |             ss << "Cannot parse url: " << url; | ||||||
| @@ -175,12 +173,7 @@ namespace ix | |||||||
|         // Build request string |         // Build request string | ||||||
|         std::stringstream ss; |         std::stringstream ss; | ||||||
|         ss << verb << " " << path << " HTTP/1.1\r\n"; |         ss << verb << " " << path << " HTTP/1.1\r\n"; | ||||||
|         ss << "Host: " << host; |         ss << "Host: " << host << "\r\n"; | ||||||
|         if (!isProtocolDefaultPort) |  | ||||||
|         { |  | ||||||
|             ss << ":" << port; |  | ||||||
|         } |  | ||||||
|         ss << "\r\n"; |  | ||||||
|  |  | ||||||
| #ifdef IXWEBSOCKET_USE_ZLIB | #ifdef IXWEBSOCKET_USE_ZLIB | ||||||
|         if (args->compress && !args->onChunkCallback) |         if (args->compress && !args->onChunkCallback) | ||||||
| @@ -209,12 +202,6 @@ namespace ix | |||||||
|             ss << "User-Agent: " << userAgent() << "\r\n"; |             ss << "User-Agent: " << userAgent() << "\r\n"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Set an origin header if missing |  | ||||||
|         if (args->extraHeaders.find("Origin") == args->extraHeaders.end()) |  | ||||||
|         { |  | ||||||
|             ss << "Origin: " << protocol << "://" << host << ":" << port << "\r\n"; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (verb == kPost || verb == kPut || verb == kPatch || _forceBody) |         if (verb == kPost || verb == kPut || verb == kPatch || _forceBody) | ||||||
|         { |         { | ||||||
|             // Set request compression header |             // Set request compression header | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ | |||||||
| #include "IXNetSystem.h" | #include "IXNetSystem.h" | ||||||
| #include "IXSocketConnect.h" | #include "IXSocketConnect.h" | ||||||
| #include "IXUserAgent.h" | #include "IXUserAgent.h" | ||||||
| #include <cstdint> |  | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <fstream> | #include <fstream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
| @@ -41,29 +40,6 @@ namespace | |||||||
|         auto vec = res.second; |         auto vec = res.second; | ||||||
|         return std::make_pair(res.first, std::string(vec.begin(), vec.end())); |         return std::make_pair(res.first, std::string(vec.begin(), vec.end())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::string response_head_file(const std::string& file_name){ |  | ||||||
|  |  | ||||||
|         if (std::string::npos != file_name.find(".html") || std::string::npos != file_name.find(".htm")) |  | ||||||
|             return "text/html"; |  | ||||||
|         else if (std::string::npos != file_name.find(".css")) |  | ||||||
|             return "text/css"; |  | ||||||
|         else if (std::string::npos != file_name.find(".js") || std::string::npos != file_name.find(".mjs")) |  | ||||||
|             return "application/x-javascript"; |  | ||||||
|         else if (std::string::npos != file_name.find(".ico")) |  | ||||||
|             return "image/x-icon"; |  | ||||||
|         else if (std::string::npos != file_name.find(".png")) |  | ||||||
|             return "image/png"; |  | ||||||
|         else if (std::string::npos != file_name.find(".jpg") || std::string::npos != file_name.find(".jpeg")) |  | ||||||
|             return "image/jpeg"; |  | ||||||
|         else if (std::string::npos != file_name.find(".gif")) |  | ||||||
|             return "image/gif"; |  | ||||||
|         else if (std::string::npos != file_name.find(".svg")) |  | ||||||
|             return "image/svg+xml"; |  | ||||||
|         else |  | ||||||
|             return "application/octet-stream"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } // namespace | } // namespace | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| @@ -75,14 +51,28 @@ namespace ix | |||||||
|                            int backlog, |                            int backlog, | ||||||
|                            size_t maxConnections, |                            size_t maxConnections, | ||||||
|                            int addressFamily, |                            int addressFamily, | ||||||
|                            int timeoutSecs, |                            int timeoutSecs) | ||||||
|                            int handshakeTimeoutSecs) |         : SocketServer(port, host, backlog, maxConnections, addressFamily) | ||||||
|         : WebSocketServer(port, host, backlog, maxConnections, handshakeTimeoutSecs, addressFamily) |         , _connectedClientsCount(0) | ||||||
|         , _timeoutSecs(timeoutSecs) |         , _timeoutSecs(timeoutSecs) | ||||||
|     { |     { | ||||||
|         setDefaultConnectionCallback(); |         setDefaultConnectionCallback(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     HttpServer::~HttpServer() | ||||||
|  |     { | ||||||
|  |         stop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void HttpServer::stop() | ||||||
|  |     { | ||||||
|  |         stopAcceptingConnections(); | ||||||
|  |  | ||||||
|  |         // FIXME: cancelling / closing active clients ... | ||||||
|  |  | ||||||
|  |         SocketServer::stop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void HttpServer::setOnConnectionCallback(const OnConnectionCallback& callback) |     void HttpServer::setOnConnectionCallback(const OnConnectionCallback& callback) | ||||||
|     { |     { | ||||||
|         _onConnectionCallback = callback; |         _onConnectionCallback = callback; | ||||||
| @@ -91,35 +81,34 @@ namespace ix | |||||||
|     void HttpServer::handleConnection(std::unique_ptr<Socket> socket, |     void HttpServer::handleConnection(std::unique_ptr<Socket> socket, | ||||||
|                                       std::shared_ptr<ConnectionState> connectionState) |                                       std::shared_ptr<ConnectionState> connectionState) | ||||||
|     { |     { | ||||||
|  |         _connectedClientsCount++; | ||||||
|  |  | ||||||
|         auto ret = Http::parseRequest(socket, _timeoutSecs); |         auto ret = Http::parseRequest(socket, _timeoutSecs); | ||||||
|         // FIXME: handle errors in parseRequest |         // FIXME: handle errors in parseRequest | ||||||
|  |  | ||||||
|         if (std::get<0>(ret)) |         if (std::get<0>(ret)) | ||||||
|         { |         { | ||||||
|             auto request = std::get<2>(ret); |             auto response = _onConnectionCallback(std::get<2>(ret), connectionState); | ||||||
|             std::shared_ptr<ix::HttpResponse> response; |             if (!Http::sendResponse(response, socket)) | ||||||
|             if (request->headers["Upgrade"] == "websocket") |  | ||||||
|             { |             { | ||||||
|                 WebSocketServer::handleUpgrade(std::move(socket), connectionState, request); |                 logError("Cannot send response"); | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 auto response = _onConnectionCallback(request, connectionState); |  | ||||||
|                 if (!Http::sendResponse(response, socket)) |  | ||||||
|                 { |  | ||||||
|                     logError("Cannot send response"); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         connectionState->setTerminated(); |         connectionState->setTerminated(); | ||||||
|  |  | ||||||
|  |         _connectedClientsCount--; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     size_t HttpServer::getConnectedClientsCount() | ||||||
|  |     { | ||||||
|  |         return _connectedClientsCount; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void HttpServer::setDefaultConnectionCallback() |     void HttpServer::setDefaultConnectionCallback() | ||||||
|     { |     { | ||||||
|         setOnConnectionCallback( |         setOnConnectionCallback( | ||||||
|             [this](HttpRequestPtr request, |             [this](HttpRequestPtr request, | ||||||
|                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr |                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr { | ||||||
|             { |  | ||||||
|                 std::string uri(request->uri); |                 std::string uri(request->uri); | ||||||
|                 if (uri.empty() || uri == "/") |                 if (uri.empty() || uri == "/") | ||||||
|                 { |                 { | ||||||
| @@ -128,7 +117,6 @@ namespace ix | |||||||
|  |  | ||||||
|                 WebSocketHttpHeaders headers; |                 WebSocketHttpHeaders headers; | ||||||
|                 headers["Server"] = userAgent(); |                 headers["Server"] = userAgent(); | ||||||
|                 headers["Content-Type"] = response_head_file(uri); |  | ||||||
|  |  | ||||||
|                 std::string path("." + uri); |                 std::string path("." + uri); | ||||||
|                 auto res = readAsString(path); |                 auto res = readAsString(path); | ||||||
| @@ -177,9 +165,9 @@ namespace ix | |||||||
|         // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections |         // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections | ||||||
|         // |         // | ||||||
|         setOnConnectionCallback( |         setOnConnectionCallback( | ||||||
|             [this, redirectUrl](HttpRequestPtr request, |             [this, | ||||||
|                                 std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr |              redirectUrl](HttpRequestPtr request, | ||||||
|             { |                           std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr { | ||||||
|                 WebSocketHttpHeaders headers; |                 WebSocketHttpHeaders headers; | ||||||
|                 headers["Server"] = userAgent(); |                 headers["Server"] = userAgent(); | ||||||
|  |  | ||||||
| @@ -210,8 +198,7 @@ namespace ix | |||||||
|     { |     { | ||||||
|         setOnConnectionCallback( |         setOnConnectionCallback( | ||||||
|             [this](HttpRequestPtr request, |             [this](HttpRequestPtr request, | ||||||
|                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr |                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr { | ||||||
|             { |  | ||||||
|                 WebSocketHttpHeaders headers; |                 WebSocketHttpHeaders headers; | ||||||
|                 headers["Server"] = userAgent(); |                 headers["Server"] = userAgent(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,8 +7,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "IXHttp.h" | #include "IXHttp.h" | ||||||
|  | #include "IXSocketServer.h" | ||||||
| #include "IXWebSocket.h" | #include "IXWebSocket.h" | ||||||
| #include "IXWebSocketServer.h" |  | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <mutex> | #include <mutex> | ||||||
| @@ -19,7 +19,7 @@ | |||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     class HttpServer final : public WebSocketServer |     class HttpServer final : public SocketServer | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         using OnConnectionCallback = |         using OnConnectionCallback = | ||||||
| @@ -30,8 +30,9 @@ namespace ix | |||||||
|                    int backlog = SocketServer::kDefaultTcpBacklog, |                    int backlog = SocketServer::kDefaultTcpBacklog, | ||||||
|                    size_t maxConnections = SocketServer::kDefaultMaxConnections, |                    size_t maxConnections = SocketServer::kDefaultMaxConnections, | ||||||
|                    int addressFamily = SocketServer::kDefaultAddressFamily, |                    int addressFamily = SocketServer::kDefaultAddressFamily, | ||||||
|                    int timeoutSecs = HttpServer::kDefaultTimeoutSecs, |                    int timeoutSecs = HttpServer::kDefaultTimeoutSecs); | ||||||
|                    int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs); |         virtual ~HttpServer(); | ||||||
|  |         virtual void stop() final; | ||||||
|  |  | ||||||
|         void setOnConnectionCallback(const OnConnectionCallback& callback); |         void setOnConnectionCallback(const OnConnectionCallback& callback); | ||||||
|  |  | ||||||
| @@ -40,10 +41,10 @@ namespace ix | |||||||
|         void makeDebugServer(); |         void makeDebugServer(); | ||||||
|  |  | ||||||
|         int getTimeoutSecs(); |         int getTimeoutSecs(); | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         // Member variables |         // Member variables | ||||||
|         OnConnectionCallback _onConnectionCallback; |         OnConnectionCallback _onConnectionCallback; | ||||||
|  |         std::atomic<int> _connectedClientsCount; | ||||||
|  |  | ||||||
|         const static int kDefaultTimeoutSecs; |         const static int kDefaultTimeoutSecs; | ||||||
|         int _timeoutSecs; |         int _timeoutSecs; | ||||||
| @@ -51,6 +52,7 @@ namespace ix | |||||||
|         // Methods |         // Methods | ||||||
|         virtual void handleConnection(std::unique_ptr<Socket>, |         virtual void handleConnection(std::unique_ptr<Socket>, | ||||||
|                                       std::shared_ptr<ConnectionState> connectionState) final; |                                       std::shared_ptr<ConnectionState> connectionState) final; | ||||||
|  |         virtual size_t getConnectedClientsCount() final; | ||||||
|  |  | ||||||
|         void setDefaultConnectionCallback(); |         void setDefaultConnectionCallback(); | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -6,12 +6,6 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
|  |  | ||||||
| #ifdef __FreeBSD__ |  | ||||||
| #include <sys/types.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|  |  | ||||||
| #ifndef WIN32_LEAN_AND_MEAN | #ifndef WIN32_LEAN_AND_MEAN | ||||||
|   | |||||||
| @@ -6,8 +6,8 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <stdint.h> | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "IXSelectInterrupt.h" | #include "IXSelectInterrupt.h" | ||||||
| #include <cstdint> |  | ||||||
| #include <mutex> | #include <mutex> | ||||||
|  | #include <stdint.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <deque> | #include <deque> | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "IXSelectInterrupt.h" | #include "IXSelectInterrupt.h" | ||||||
| #include <cstdint> |  | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <string> | #include <string> | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
| #include <array> | #include <array> | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
|  | #include <stdint.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstdint> |  | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <mutex> | #include <mutex> | ||||||
|   | |||||||
| @@ -205,9 +205,7 @@ namespace ix | |||||||
|                 _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket); |                 _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket); | ||||||
|             SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd); |             SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd); | ||||||
|             SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12); |             SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12); | ||||||
|  |             SSLSetPeerDomainName(_sslContext, host.c_str(), host.size()); | ||||||
|             if (!_tlsOptions.disable_hostname_validation) |  | ||||||
|                 SSLSetPeerDomainName(_sslContext, host.c_str(), host.size()); |  | ||||||
|  |  | ||||||
|             if (_tlsOptions.isPeerVerifyDisabled()) |             if (_tlsOptions.isPeerVerifyDisabled()) | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -102,7 +102,7 @@ namespace ix | |||||||
|         // First do DNS resolution |         // First do DNS resolution | ||||||
|         // |         // | ||||||
|         auto dnsLookup = std::make_shared<DNSLookup>(hostname, port); |         auto dnsLookup = std::make_shared<DNSLookup>(hostname, port); | ||||||
|         auto res = dnsLookup->resolve(errMsg, isCancellationRequested); |         struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested); | ||||||
|         if (res == nullptr) |         if (res == nullptr) | ||||||
|         { |         { | ||||||
|             return -1; |             return -1; | ||||||
| @@ -112,7 +112,7 @@ namespace ix | |||||||
|  |  | ||||||
|         // iterate through the records to find a working peer |         // iterate through the records to find a working peer | ||||||
|         struct addrinfo* address; |         struct addrinfo* address; | ||||||
|         for (address = res.get(); address != nullptr; address = address->ai_next) |         for (address = res; address != nullptr; address = address->ai_next) | ||||||
|         { |         { | ||||||
|             // |             // | ||||||
|             // Second try to connect to the remote host |             // Second try to connect to the remote host | ||||||
| @@ -124,6 +124,7 @@ namespace ix | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         freeaddrinfo(res); | ||||||
|         return sockfd; |         return sockfd; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,7 +14,6 @@ | |||||||
| #include "IXNetSystem.h" | #include "IXNetSystem.h" | ||||||
| #include "IXSocket.h" | #include "IXSocket.h" | ||||||
| #include "IXSocketConnect.h" | #include "IXSocketConnect.h" | ||||||
| #include <cstdint> |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  |  | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| @@ -49,7 +48,7 @@ namespace ix | |||||||
|         mbedtls_pk_init(&_pkey); |         mbedtls_pk_init(&_pkey); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool SocketMbedTLS::loadSystemCertificates(std::string& /* errorMsg */) |     bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg) | ||||||
|     { |     { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|         DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | |         DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | | ||||||
| @@ -196,13 +195,10 @@ namespace ix | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!_tlsOptions.disable_hostname_validation) |         if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0) | ||||||
|         { |         { | ||||||
|             if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0) |             errMsg = "SNI setup failed"; | ||||||
|             { |             return false; | ||||||
|                 errMsg = "SNI setup failed"; |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|   | |||||||
| @@ -301,11 +301,7 @@ namespace ix | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl, |     bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl, | ||||||
| #if OPENSSL_VERSION_NUMBER < 0x10100000L |  | ||||||
|                                                const std::string& hostname, |                                                const std::string& hostname, | ||||||
| #else |  | ||||||
|                                                const std::string& /* hostname */, |  | ||||||
| #endif |  | ||||||
|                                                std::string& errMsg) |                                                std::string& errMsg) | ||||||
|     { |     { | ||||||
|         X509* server_cert = SSL_get_peer_certificate(ssl); |         X509* server_cert = SSL_get_peer_certificate(ssl); | ||||||
| @@ -394,11 +390,6 @@ namespace ix | |||||||
|             int connect_result = SSL_connect(_ssl_connection); |             int connect_result = SSL_connect(_ssl_connection); | ||||||
|             if (connect_result == 1) |             if (connect_result == 1) | ||||||
|             { |             { | ||||||
|                 if (_tlsOptions.disable_hostname_validation) |  | ||||||
|                 { |  | ||||||
|                     return true; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 return openSSLCheckServerCert(_ssl_connection, host, errMsg); |                 return openSSLCheckServerCert(_ssl_connection, host, errMsg); | ||||||
|             } |             } | ||||||
|             int reason = SSL_get_error(_ssl_connection, connect_result); |             int reason = SSL_get_error(_ssl_connection, connect_result); | ||||||
| @@ -763,11 +754,8 @@ namespace ix | |||||||
|             // (The docs say that this should work from 1.0.2, and is the default from |             // (The docs say that this should work from 1.0.2, and is the default from | ||||||
|             // 1.1.0, but it does not. To be on the safe side, the manual test |             // 1.1.0, but it does not. To be on the safe side, the manual test | ||||||
|             // below is enabled for all versions prior to 1.1.0.) |             // below is enabled for all versions prior to 1.1.0.) | ||||||
|             if (!_tlsOptions.disable_hostname_validation) |             X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection); | ||||||
|             { |             X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0); | ||||||
|                 X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection); |  | ||||||
|                 X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size()); |  | ||||||
|             } |  | ||||||
| #endif | #endif | ||||||
|             handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested); |             handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -219,10 +219,6 @@ namespace ix | |||||||
|         if (_gcThread.joinable()) |         if (_gcThread.joinable()) | ||||||
|         { |         { | ||||||
|             _stopGc = true; |             _stopGc = true; | ||||||
|             { |  | ||||||
|                 std::lock_guard<std::mutex> lock{ _conditionVariableMutexGC }; |  | ||||||
|                 _canContinueGC = true; |  | ||||||
|             } |  | ||||||
|             _conditionVariableGC.notify_one(); |             _conditionVariableGC.notify_one(); | ||||||
|             _gcThread.join(); |             _gcThread.join(); | ||||||
|             _stopGc = false; |             _stopGc = false; | ||||||
| @@ -272,10 +268,7 @@ namespace ix | |||||||
|         // Set the socket to non blocking mode, so that accept calls are not blocking |         // Set the socket to non blocking mode, so that accept calls are not blocking | ||||||
|         SocketConnect::configure(_serverFd); |         SocketConnect::configure(_serverFd); | ||||||
|  |  | ||||||
|         // Use a cryptic name to stay within the 16 bytes limit thread name limitation |         setThreadName("SocketServer::accept"); | ||||||
|         // $ echo Srv:gc:64000 | wc -c |  | ||||||
|         // 13 |  | ||||||
|         setThreadName("Srv:ac:" + std::to_string(_port)); |  | ||||||
|  |  | ||||||
|         for (;;) |         for (;;) | ||||||
|         { |         { | ||||||
| @@ -432,10 +425,7 @@ namespace ix | |||||||
|  |  | ||||||
|     void SocketServer::runGC() |     void SocketServer::runGC() | ||||||
|     { |     { | ||||||
|         // Use a cryptic name to stay within the 16 bytes limit thread name limitation |         setThreadName("SocketServer::GC"); | ||||||
|         // $ echo Srv:gc:64000 | wc -c |  | ||||||
|         // 13 |  | ||||||
|         setThreadName("Srv:gc:" + std::to_string(_port)); |  | ||||||
|  |  | ||||||
|         for (;;) |         for (;;) | ||||||
|         { |         { | ||||||
| @@ -455,10 +445,7 @@ namespace ix | |||||||
|             if (!_stopGc) |             if (!_stopGc) | ||||||
|             { |             { | ||||||
|                 std::unique_lock<std::mutex> lock(_conditionVariableMutexGC); |                 std::unique_lock<std::mutex> lock(_conditionVariableMutexGC); | ||||||
|                 if(!_canContinueGC) { |                 _conditionVariableGC.wait(lock); | ||||||
|                     _conditionVariableGC.wait(lock, [this]{ return _canContinueGC; }); |  | ||||||
|                 } |  | ||||||
|                 _canContinueGC = false; |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -472,10 +459,6 @@ namespace ix | |||||||
|     { |     { | ||||||
|         // a connection got terminated, we can run the connection thread GC, |         // a connection got terminated, we can run the connection thread GC, | ||||||
|         // so wake up the thread responsible for that |         // so wake up the thread responsible for that | ||||||
|         { |  | ||||||
|             std::lock_guard<std::mutex> lock{ _conditionVariableMutexGC }; |  | ||||||
|             _canContinueGC = true; |  | ||||||
|         } |  | ||||||
|         _conditionVariableGC.notify_one(); |         _conditionVariableGC.notify_one(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -126,6 +126,5 @@ namespace ix | |||||||
|         // as a connection |         // as a connection | ||||||
|         std::condition_variable _conditionVariableGC; |         std::condition_variable _conditionVariableGC; | ||||||
|         std::mutex _conditionVariableMutexGC; |         std::mutex _conditionVariableMutexGC; | ||||||
|         bool _canContinueGC{ false }; |  | ||||||
|     }; |     }; | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
| @@ -33,9 +33,6 @@ namespace ix | |||||||
|         // whether tls is enabled, used for server code |         // whether tls is enabled, used for server code | ||||||
|         bool tls = false; |         bool tls = false; | ||||||
|  |  | ||||||
|         // whether to skip validating the peer's hostname against the certificate presented |  | ||||||
|         bool disable_hostname_validation = false; |  | ||||||
|  |  | ||||||
|         bool hasCertAndKey() const; |         bool hasCertAndKey() const; | ||||||
|  |  | ||||||
|         bool isUsingSystemDefaults() const; |         bool isUsingSystemDefaults() const; | ||||||
|   | |||||||
| @@ -333,19 +333,6 @@ namespace | |||||||
|  |  | ||||||
|         return Result; |         return Result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     int getProtocolPort(const std::string& protocol) |  | ||||||
|     { |  | ||||||
|         if (protocol == "ws" || protocol == "http") |  | ||||||
|         { |  | ||||||
|             return 80; |  | ||||||
|         } |  | ||||||
|         else if (protocol == "wss" || protocol == "https") |  | ||||||
|         { |  | ||||||
|             return 443; |  | ||||||
|         } |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| } // namespace | } // namespace | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| @@ -356,18 +343,6 @@ namespace ix | |||||||
|                           std::string& path, |                           std::string& path, | ||||||
|                           std::string& query, |                           std::string& query, | ||||||
|                           int& port) |                           int& port) | ||||||
|     { |  | ||||||
|         bool isProtocolDefaultPort; |  | ||||||
|         return parse(url, protocol, host, path, query, port, isProtocolDefaultPort); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool UrlParser::parse(const std::string& url, |  | ||||||
|                               std::string& protocol, |  | ||||||
|                               std::string& host, |  | ||||||
|                               std::string& path, |  | ||||||
|                               std::string& query, |  | ||||||
|                               int& port, |  | ||||||
|                               bool& isProtocolDefaultPort) |  | ||||||
|     { |     { | ||||||
|         clParseURL res = clParseURL::ParseURL(url); |         clParseURL res = clParseURL::ParseURL(url); | ||||||
|  |  | ||||||
| @@ -381,12 +356,23 @@ namespace ix | |||||||
|         path = res.m_Path; |         path = res.m_Path; | ||||||
|         query = res.m_Query; |         query = res.m_Query; | ||||||
|  |  | ||||||
|         const auto protocolPort = getProtocolPort(protocol); |  | ||||||
|         if (!res.GetPort(&port)) |         if (!res.GetPort(&port)) | ||||||
|         { |         { | ||||||
|             port = protocolPort; |             if (protocol == "ws" || protocol == "http") | ||||||
|  |             { | ||||||
|  |                 port = 80; | ||||||
|  |             } | ||||||
|  |             else if (protocol == "wss" || protocol == "https") | ||||||
|  |             { | ||||||
|  |                 port = 443; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 // Invalid protocol. Should be caught by regex check | ||||||
|  |                 // but this missing branch trigger cpplint linter. | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         isProtocolDefaultPort = port == protocolPort; |  | ||||||
|  |  | ||||||
|         if (path.empty()) |         if (path.empty()) | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -19,13 +19,5 @@ namespace ix | |||||||
|                           std::string& path, |                           std::string& path, | ||||||
|                           std::string& query, |                           std::string& query, | ||||||
|                           int& port); |                           int& port); | ||||||
|  |  | ||||||
|         static bool parse(const std::string& url, |  | ||||||
|                           std::string& protocol, |  | ||||||
|                           std::string& host, |  | ||||||
|                           std::string& path, |  | ||||||
|                           std::string& query, |  | ||||||
|                           int& port, |  | ||||||
|                           bool& isProtocolDefaultPort); |  | ||||||
|     }; |     }; | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
| @@ -16,7 +16,6 @@ | |||||||
|  |  | ||||||
| #include "IXUuid.h" | #include "IXUuid.h" | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
| #include <random> | #include <random> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|   | |||||||
| @@ -13,7 +13,6 @@ | |||||||
| #include "IXWebSocketHandshake.h" | #include "IXWebSocketHandshake.h" | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <cmath> | #include <cmath> | ||||||
| #include <cstdint> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| namespace | namespace | ||||||
| @@ -40,11 +39,9 @@ namespace ix | |||||||
|         , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs) |         , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs) | ||||||
|         , _enablePong(kDefaultEnablePong) |         , _enablePong(kDefaultEnablePong) | ||||||
|         , _pingIntervalSecs(kDefaultPingIntervalSecs) |         , _pingIntervalSecs(kDefaultPingIntervalSecs) | ||||||
|         , _pingType(SendMessageKind::Ping) |  | ||||||
|     { |     { | ||||||
|         _ws.setOnCloseCallback( |         _ws.setOnCloseCallback( | ||||||
|             [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) |             [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) { | ||||||
|             { |  | ||||||
|                 _onMessageCallback( |                 _onMessageCallback( | ||||||
|                     ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close, |                     ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close, | ||||||
|                                                       emptyMsg, |                                                       emptyMsg, | ||||||
| @@ -103,17 +100,6 @@ namespace ix | |||||||
|         return _perMessageDeflateOptions; |         return _perMessageDeflateOptions; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void WebSocket::setPingMessage(const std::string& sendMessage, SendMessageKind pingType) |  | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(_configMutex); |  | ||||||
|         _pingMessage = sendMessage; |  | ||||||
|         _ws.setPingMessage(_pingMessage, pingType); |  | ||||||
|     } |  | ||||||
|     const std::string WebSocket::getPingMessage() const |  | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(_configMutex); |  | ||||||
|         return _pingMessage; |  | ||||||
|     } |  | ||||||
|     void WebSocket::setPingInterval(int pingIntervalSecs) |     void WebSocket::setPingInterval(int pingIntervalSecs) | ||||||
|     { |     { | ||||||
|         std::lock_guard<std::mutex> lock(_configMutex); |         std::lock_guard<std::mutex> lock(_configMutex); | ||||||
| @@ -246,7 +232,7 @@ namespace ix | |||||||
|         if (_pingIntervalSecs > 0) |         if (_pingIntervalSecs > 0) | ||||||
|         { |         { | ||||||
|             // Send a heart beat right away |             // Send a heart beat right away | ||||||
|             _ws.sendHeartBeat(_pingType); |             _ws.sendHeartBeat(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return status; |         return status; | ||||||
| @@ -254,8 +240,7 @@ namespace ix | |||||||
|  |  | ||||||
|     WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket, |     WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket, | ||||||
|                                                    int timeoutSecs, |                                                    int timeoutSecs, | ||||||
|                                                    bool enablePerMessageDeflate, |                                                    bool enablePerMessageDeflate) | ||||||
|                                                    HttpRequestPtr request) |  | ||||||
|     { |     { | ||||||
|         { |         { | ||||||
|             std::lock_guard<std::mutex> lock(_configMutex); |             std::lock_guard<std::mutex> lock(_configMutex); | ||||||
| @@ -264,7 +249,7 @@ namespace ix | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         WebSocketInitResult status = |         WebSocketInitResult status = | ||||||
|             _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate, request); |             _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate); | ||||||
|         if (!status.success) |         if (!status.success) | ||||||
|         { |         { | ||||||
|             return status; |             return status; | ||||||
| @@ -281,7 +266,7 @@ namespace ix | |||||||
|         if (_pingIntervalSecs > 0) |         if (_pingIntervalSecs > 0) | ||||||
|         { |         { | ||||||
|             // Send a heart beat right away |             // Send a heart beat right away | ||||||
|             _ws.sendHeartBeat(_pingType); |             _ws.sendHeartBeat(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return status; |         return status; | ||||||
| @@ -399,9 +384,8 @@ namespace ix | |||||||
|                 [this](const std::string& msg, |                 [this](const std::string& msg, | ||||||
|                        size_t wireSize, |                        size_t wireSize, | ||||||
|                        bool decompressionError, |                        bool decompressionError, | ||||||
|                        WebSocketTransport::MessageKind messageKind) |                        WebSocketTransport::MessageKind messageKind) { | ||||||
|                 { |                     WebSocketMessageType webSocketMessageType{WebSocketMessageType::Error}; | ||||||
|                     WebSocketMessageType webSocketMessageType {WebSocketMessageType::Error}; |  | ||||||
|                     switch (messageKind) |                     switch (messageKind) | ||||||
|                     { |                     { | ||||||
|                         case WebSocketTransport::MessageKind::MSG_TEXT: |                         case WebSocketTransport::MessageKind::MSG_TEXT: | ||||||
| @@ -519,13 +503,13 @@ namespace ix | |||||||
|         return sendMessage(text, SendMessageKind::Text, onProgressCallback); |         return sendMessage(text, SendMessageKind::Text, onProgressCallback); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     WebSocketSendInfo WebSocket::ping(const std::string& text, SendMessageKind pingType) |     WebSocketSendInfo WebSocket::ping(const std::string& text) | ||||||
|     { |     { | ||||||
|         // Standard limit ping message size |         // Standard limit ping message size | ||||||
|         constexpr size_t pingMaxPayloadSize = 125; |         constexpr size_t pingMaxPayloadSize = 125; | ||||||
|         if (text.size() > pingMaxPayloadSize) return WebSocketSendInfo(false); |         if (text.size() > pingMaxPayloadSize) return WebSocketSendInfo(false); | ||||||
|  |  | ||||||
|         return sendMessage(text, pingType); |         return sendMessage(text, SendMessageKind::Ping); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     WebSocketSendInfo WebSocket::sendMessage(const IXWebSocketSendData& message, |     WebSocketSendInfo WebSocket::sendMessage(const IXWebSocketSendData& message, | ||||||
|   | |||||||
| @@ -16,12 +16,11 @@ | |||||||
| #include "IXWebSocketHttpHeaders.h" | #include "IXWebSocketHttpHeaders.h" | ||||||
| #include "IXWebSocketMessage.h" | #include "IXWebSocketMessage.h" | ||||||
| #include "IXWebSocketPerMessageDeflateOptions.h" | #include "IXWebSocketPerMessageDeflateOptions.h" | ||||||
| #include "IXWebSocketSendData.h" |  | ||||||
| #include "IXWebSocketSendInfo.h" | #include "IXWebSocketSendInfo.h" | ||||||
|  | #include "IXWebSocketSendData.h" | ||||||
| #include "IXWebSocketTransport.h" | #include "IXWebSocketTransport.h" | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <condition_variable> | #include <condition_variable> | ||||||
| #include <cstdint> |  | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| @@ -54,8 +53,6 @@ namespace ix | |||||||
|         void setPerMessageDeflateOptions( |         void setPerMessageDeflateOptions( | ||||||
|             const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions); |             const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions); | ||||||
|         void setTLSOptions(const SocketTLSOptions& socketTLSOptions); |         void setTLSOptions(const SocketTLSOptions& socketTLSOptions); | ||||||
|         void setPingMessage(const std::string& sendMessage, |  | ||||||
|                             SendMessageKind pingType = SendMessageKind::Ping); |  | ||||||
|         void setPingInterval(int pingIntervalSecs); |         void setPingInterval(int pingIntervalSecs); | ||||||
|         void enablePong(); |         void enablePong(); | ||||||
|         void disablePong(); |         void disablePong(); | ||||||
| @@ -91,7 +88,7 @@ namespace ix | |||||||
|                                        const OnProgressCallback& onProgressCallback = nullptr); |                                        const OnProgressCallback& onProgressCallback = nullptr); | ||||||
|         WebSocketSendInfo sendText(const std::string& text, |         WebSocketSendInfo sendText(const std::string& text, | ||||||
|                                    const OnProgressCallback& onProgressCallback = nullptr); |                                    const OnProgressCallback& onProgressCallback = nullptr); | ||||||
|         WebSocketSendInfo ping(const std::string& text,SendMessageKind pingType = SendMessageKind::Ping); |         WebSocketSendInfo ping(const std::string& text); | ||||||
|  |  | ||||||
|         void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, |         void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, | ||||||
|                    const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage); |                    const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage); | ||||||
| @@ -106,7 +103,6 @@ namespace ix | |||||||
|  |  | ||||||
|         const std::string getUrl() const; |         const std::string getUrl() const; | ||||||
|         const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const; |         const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const; | ||||||
|         const std::string getPingMessage() const; |  | ||||||
|         int getPingInterval() const; |         int getPingInterval() const; | ||||||
|         size_t bufferedAmount() const; |         size_t bufferedAmount() const; | ||||||
|  |  | ||||||
| @@ -132,8 +128,7 @@ namespace ix | |||||||
|         // Server |         // Server | ||||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, |         WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, | ||||||
|                                             int timeoutSecs, |                                             int timeoutSecs, | ||||||
|                                             bool enablePerMessageDeflate, |                                             bool enablePerMessageDeflate); | ||||||
|                                             HttpRequestPtr request = nullptr); |  | ||||||
|  |  | ||||||
|         WebSocketTransport _ws; |         WebSocketTransport _ws; | ||||||
|  |  | ||||||
| @@ -174,8 +169,6 @@ namespace ix | |||||||
|         // Optional ping and pong timeout |         // Optional ping and pong timeout | ||||||
|         int _pingIntervalSecs; |         int _pingIntervalSecs; | ||||||
|         int _pingTimeoutSecs; |         int _pingTimeoutSecs; | ||||||
|         std::string _pingMessage; |  | ||||||
|         SendMessageKind _pingType; |  | ||||||
|         static const int kDefaultPingIntervalSecs; |         static const int kDefaultPingIntervalSecs; | ||||||
|         static const int kDefaultPingTimeoutSecs; |         static const int kDefaultPingTimeoutSecs; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ | |||||||
|  |  | ||||||
| #include "IXWebSocketHandshake.h" | #include "IXWebSocketHandshake.h" | ||||||
|  |  | ||||||
| #include "IXBase64.h" |  | ||||||
| #include "IXHttp.h" | #include "IXHttp.h" | ||||||
| #include "IXSocketConnect.h" | #include "IXSocketConnect.h" | ||||||
| #include "IXStrCaseCompare.h" | #include "IXStrCaseCompare.h" | ||||||
| @@ -18,6 +17,7 @@ | |||||||
| #include <random> | #include <random> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|  |  | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|     WebSocketHandshake::WebSocketHandshake( |     WebSocketHandshake::WebSocketHandshake( | ||||||
| @@ -87,7 +87,6 @@ namespace ix | |||||||
|     WebSocketInitResult WebSocketHandshake::clientHandshake( |     WebSocketInitResult WebSocketHandshake::clientHandshake( | ||||||
|         const std::string& url, |         const std::string& url, | ||||||
|         const WebSocketHttpHeaders& extraHeaders, |         const WebSocketHttpHeaders& extraHeaders, | ||||||
|         const std::string& protocol, |  | ||||||
|         const std::string& host, |         const std::string& host, | ||||||
|         const std::string& path, |         const std::string& path, | ||||||
|         int port, |         int port, | ||||||
| @@ -107,10 +106,15 @@ namespace ix | |||||||
|             return WebSocketInitResult(false, 0, ss.str()); |             return WebSocketInitResult(false, 0, ss.str()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Generate a random 16 bytes string and base64 encode it. |         // | ||||||
|  |         // Generate a random 24 bytes string which looks like it is base64 encoded | ||||||
|  |         // y3JJHMbDL1EzLkh9GBhXDw== | ||||||
|  |         // 0cb3Vd9HkbpVVumoS3Noka== | ||||||
|         // |         // | ||||||
|         // See https://stackoverflow.com/questions/18265128/what-is-sec-websocket-key-for |         // See https://stackoverflow.com/questions/18265128/what-is-sec-websocket-key-for | ||||||
|         std::string secWebSocketKey = macaron::Base64::Encode(genRandomString(16)); |         // | ||||||
|  |         std::string secWebSocketKey = genRandomString(22); | ||||||
|  |         secWebSocketKey += "=="; | ||||||
|  |  | ||||||
|         std::stringstream ss; |         std::stringstream ss; | ||||||
|         ss << "GET " << path << " HTTP/1.1\r\n"; |         ss << "GET " << path << " HTTP/1.1\r\n"; | ||||||
| @@ -126,12 +130,6 @@ namespace ix | |||||||
|             ss << "User-Agent: " << userAgent() << "\r\n"; |             ss << "User-Agent: " << userAgent() << "\r\n"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Set an origin header if missing |  | ||||||
|         if (extraHeaders.find("Origin") == extraHeaders.end()) |  | ||||||
|         { |  | ||||||
|             ss << "Origin: " << protocol << "://" << host << ":" << port << "\r\n"; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (auto& it : extraHeaders) |         for (auto& it : extraHeaders) | ||||||
|         { |         { | ||||||
|             ss << it.first << ": " << it.second << "\r\n"; |             ss << it.first << ": " << it.second << "\r\n"; | ||||||
| @@ -247,42 +245,28 @@ namespace ix | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs, |     WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs, | ||||||
|                                                             bool enablePerMessageDeflate, |                                                             bool enablePerMessageDeflate) | ||||||
|                                                             HttpRequestPtr request) |  | ||||||
|     { |     { | ||||||
|         _requestInitCancellation = false; |         _requestInitCancellation = false; | ||||||
|  |  | ||||||
|         auto isCancellationRequested = |         auto isCancellationRequested = | ||||||
|             makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation); |             makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation); | ||||||
|  |  | ||||||
|         std::string method; |         // Read first line | ||||||
|         std::string uri; |         auto lineResult = _socket->readLine(isCancellationRequested); | ||||||
|         std::string httpVersion; |         auto lineValid = lineResult.first; | ||||||
|  |         auto line = lineResult.second; | ||||||
|  |  | ||||||
|         if (request) |         if (!lineValid) | ||||||
|         { |         { | ||||||
|             method = request->method; |             return sendErrorResponse(400, "Error reading HTTP request line"); | ||||||
|             uri = request->uri; |  | ||||||
|             httpVersion = request->version; |  | ||||||
|         } |         } | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             // Read first line |  | ||||||
|             auto lineResult = _socket->readLine(isCancellationRequested); |  | ||||||
|             auto lineValid = lineResult.first; |  | ||||||
|             auto line = lineResult.second; |  | ||||||
|  |  | ||||||
|             if (!lineValid) |         // Validate request line (GET /foo HTTP/1.1\r\n) | ||||||
|             { |         auto requestLine = Http::parseRequestLine(line); | ||||||
|                 return sendErrorResponse(400, "Error reading HTTP request line"); |         auto method = std::get<0>(requestLine); | ||||||
|             } |         auto uri = std::get<1>(requestLine); | ||||||
|  |         auto httpVersion = std::get<2>(requestLine); | ||||||
|             // Validate request line (GET /foo HTTP/1.1\r\n) |  | ||||||
|             auto requestLine = Http::parseRequestLine(line); |  | ||||||
|             method = std::get<0>(requestLine); |  | ||||||
|             uri = std::get<1>(requestLine); |  | ||||||
|             httpVersion = std::get<2>(requestLine); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (method != "GET") |         if (method != "GET") | ||||||
|         { |         { | ||||||
| @@ -295,22 +279,14 @@ namespace ix | |||||||
|                                      "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion); |                                      "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         WebSocketHttpHeaders headers; |         // Retrieve and validate HTTP headers | ||||||
|         if (request) |         auto result = parseHttpHeaders(_socket, isCancellationRequested); | ||||||
|         { |         auto headersValid = result.first; | ||||||
|             headers = request->headers; |         auto headers = result.second; | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             // Retrieve and validate HTTP headers |  | ||||||
|             auto result = parseHttpHeaders(_socket, isCancellationRequested); |  | ||||||
|             auto headersValid = result.first; |  | ||||||
|             headers = result.second; |  | ||||||
|  |  | ||||||
|             if (!headersValid) |         if (!headersValid) | ||||||
|             { |         { | ||||||
|                 return sendErrorResponse(400, "Error parsing HTTP headers"); |             return sendErrorResponse(400, "Error parsing HTTP headers"); | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (headers.find("sec-websocket-key") == headers.end()) |         if (headers.find("sec-websocket-key") == headers.end()) | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "IXCancellationRequest.h" | #include "IXCancellationRequest.h" | ||||||
| #include "IXHttp.h" |  | ||||||
| #include "IXSocket.h" | #include "IXSocket.h" | ||||||
| #include "IXWebSocketHttpHeaders.h" | #include "IXWebSocketHttpHeaders.h" | ||||||
| #include "IXWebSocketInitResult.h" | #include "IXWebSocketInitResult.h" | ||||||
| @@ -31,15 +30,12 @@ namespace ix | |||||||
|  |  | ||||||
|         WebSocketInitResult clientHandshake(const std::string& url, |         WebSocketInitResult clientHandshake(const std::string& url, | ||||||
|                                             const WebSocketHttpHeaders& extraHeaders, |                                             const WebSocketHttpHeaders& extraHeaders, | ||||||
|                                             const std::string& protocol, |  | ||||||
|                                             const std::string& host, |                                             const std::string& host, | ||||||
|                                             const std::string& path, |                                             const std::string& path, | ||||||
|                                             int port, |                                             int port, | ||||||
|                                             int timeoutSecs); |                                             int timeoutSecs); | ||||||
|  |  | ||||||
|         WebSocketInitResult serverHandshake(int timeoutSecs, |         WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate); | ||||||
|                                             bool enablePerMessageDeflate, |  | ||||||
|                                             HttpRequestPtr request = nullptr); |  | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         std::string genRandomString(const int len); |         std::string genRandomString(const int len); | ||||||
|   | |||||||
| @@ -46,8 +46,6 @@ | |||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
|  |  | ||||||
| #include "IXWebSocketPerMessageDeflate.h" | #include "IXWebSocketPerMessageDeflate.h" | ||||||
|  |  | ||||||
| #include "IXUniquePtr.h" | #include "IXUniquePtr.h" | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ | |||||||
| #include "zlib.h" | #include "zlib.h" | ||||||
| #endif | #endif | ||||||
| #include <array> | #include <array> | ||||||
| #include <cstdint> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include "IXWebSocketSendData.h" | #include "IXWebSocketSendData.h" | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
|   | |||||||
| @@ -1,129 +1,128 @@ | |||||||
| /* | /* | ||||||
|  *  IXWebSocketSendData.h |  *  IXWebSocketSendData.h | ||||||
|  * |  * | ||||||
|  *  WebSocket (Binary/Text) send data buffer |  *  WebSocket (Binary/Text) send data buffer | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <cstdint> | #include <string> | ||||||
| #include <string> | #include <vector> | ||||||
| #include <vector> | #include <iterator> | ||||||
| #include <iterator> |  | ||||||
|  | namespace ix | ||||||
| namespace ix | { | ||||||
| { |     /* | ||||||
|     /* |     * IXWebSocketSendData implements a wrapper for std::string, std:vector<char/uint8_t> and char*. | ||||||
|     * IXWebSocketSendData implements a wrapper for std::string, std:vector<char/uint8_t> and char*. |     * It removes the necessarity to copy the data or string into a std::string  | ||||||
|     * It removes the necessarity to copy the data or string into a std::string  |     */ | ||||||
|     */ |     class IXWebSocketSendData { | ||||||
|     class IXWebSocketSendData { |     public: | ||||||
|     public: |  | ||||||
|  |         template<typename T> | ||||||
|         template<typename T> |         struct IXWebSocketSendData_const_iterator | ||||||
|         struct IXWebSocketSendData_const_iterator |             //: public std::iterator<std::forward_iterator_tag, T> | ||||||
|             //: public std::iterator<std::forward_iterator_tag, T> |         { | ||||||
|         { |             typedef IXWebSocketSendData_const_iterator<T> const_iterator; | ||||||
|             typedef IXWebSocketSendData_const_iterator<T> const_iterator; |  | ||||||
|  |             using iterator_category = std::forward_iterator_tag; | ||||||
|             using iterator_category = std::forward_iterator_tag; |             using difference_type = std::ptrdiff_t; | ||||||
|             using difference_type = std::ptrdiff_t; |             using value_type = T; | ||||||
|             using value_type = T; |             using pointer = value_type*; | ||||||
|             using pointer = value_type*; |             using reference = const value_type&; | ||||||
|             using reference = const value_type&; |  | ||||||
|  |             pointer _ptr; | ||||||
|             pointer _ptr; |         public: | ||||||
|         public: |             IXWebSocketSendData_const_iterator() : _ptr(nullptr) {} | ||||||
|             IXWebSocketSendData_const_iterator() : _ptr(nullptr) {} |             IXWebSocketSendData_const_iterator(pointer ptr) : _ptr(ptr) {} | ||||||
|             IXWebSocketSendData_const_iterator(pointer ptr) : _ptr(ptr) {} |             ~IXWebSocketSendData_const_iterator() {} | ||||||
|             ~IXWebSocketSendData_const_iterator() {} |  | ||||||
|  |             const_iterator  operator++(int) { return const_iterator(_ptr++); } | ||||||
|             const_iterator  operator++(int) { return const_iterator(_ptr++); } |             const_iterator& operator++() { ++_ptr; return *this; } | ||||||
|             const_iterator& operator++() { ++_ptr; return *this; } |             reference       operator* () const { return *_ptr; } | ||||||
|             reference       operator* () const { return *_ptr; } |             pointer         operator->() const { return _ptr; } | ||||||
|             pointer         operator->() const { return _ptr; } |             const_iterator  operator+ (const difference_type offset) const { return const_iterator(_ptr + offset); } | ||||||
|             const_iterator  operator+ (const difference_type offset) const { return const_iterator(_ptr + offset); } |             const_iterator  operator- (const difference_type offset) const { return const_iterator(_ptr - offset); } | ||||||
|             const_iterator  operator- (const difference_type offset) const { return const_iterator(_ptr - offset); } |             difference_type operator- (const const_iterator& rhs) const { return _ptr - rhs._ptr; } | ||||||
|             difference_type operator- (const const_iterator& rhs) const { return _ptr - rhs._ptr; } |             bool            operator==(const const_iterator& rhs) const { return _ptr == rhs._ptr; } | ||||||
|             bool            operator==(const const_iterator& rhs) const { return _ptr == rhs._ptr; } |             bool            operator!=(const const_iterator& rhs) const { return _ptr != rhs._ptr; } | ||||||
|             bool            operator!=(const const_iterator& rhs) const { return _ptr != rhs._ptr; } |             const_iterator& operator+=(const difference_type offset) { _ptr += offset; return *this; } | ||||||
|             const_iterator& operator+=(const difference_type offset) { _ptr += offset; return *this; } |             const_iterator& operator-=(const difference_type offset) { _ptr -= offset; return *this; } | ||||||
|             const_iterator& operator-=(const difference_type offset) { _ptr -= offset; return *this; } |         }; | ||||||
|         }; |  | ||||||
|  |         using const_iterator = IXWebSocketSendData_const_iterator<char>; | ||||||
|         using const_iterator = IXWebSocketSendData_const_iterator<char>; |  | ||||||
|  |         /* The assigned std::string must be kept alive for the lifetime of the input buffer */ | ||||||
|         /* The assigned std::string must be kept alive for the lifetime of the input buffer */ |         IXWebSocketSendData(const std::string& str) | ||||||
|         IXWebSocketSendData(const std::string& str) |             : _data(str.data()) | ||||||
|             : _data(str.data()) |             , _size(str.size()) | ||||||
|             , _size(str.size()) |         { | ||||||
|         { |         } | ||||||
|         } |  | ||||||
|  |         /* The assigned std::vector must be kept alive for the lifetime of the input buffer */ | ||||||
|         /* The assigned std::vector must be kept alive for the lifetime of the input buffer */ |         IXWebSocketSendData(const std::vector<char>& v) | ||||||
|         IXWebSocketSendData(const std::vector<char>& v) |             : _data(v.data()) | ||||||
|             : _data(v.data()) |             , _size(v.size()) | ||||||
|             , _size(v.size()) |         { | ||||||
|         { |         } | ||||||
|         } |  | ||||||
|  |         /* The assigned std::vector must be kept alive for the lifetime of the input buffer */ | ||||||
|         /* The assigned std::vector must be kept alive for the lifetime of the input buffer */ |         IXWebSocketSendData(const std::vector<uint8_t>& v) | ||||||
|         IXWebSocketSendData(const std::vector<uint8_t>& v) |             : _data(reinterpret_cast<const char*>(v.data())) | ||||||
|             : _data(reinterpret_cast<const char*>(v.data())) |             , _size(v.size()) | ||||||
|             , _size(v.size()) |         { | ||||||
|         { |         } | ||||||
|         } |  | ||||||
|  |         /* The assigned memory must be kept alive for the lifetime of the input buffer */ | ||||||
|         /* The assigned memory must be kept alive for the lifetime of the input buffer */ |         IXWebSocketSendData(const char* data, size_t size) | ||||||
|         IXWebSocketSendData(const char* data, size_t size) |             : _data(data) | ||||||
|             : _data(data) |             , _size(data == nullptr ? 0 : size) | ||||||
|             , _size(data == nullptr ? 0 : size) |         { | ||||||
|         { |         } | ||||||
|         } |  | ||||||
|  |         bool empty() const | ||||||
|         bool empty() const |         { | ||||||
|         { |             return _data == nullptr || _size == 0; | ||||||
|             return _data == nullptr || _size == 0; |         } | ||||||
|         } |  | ||||||
|  |         const char* c_str() const | ||||||
|         const char* c_str() const |         { | ||||||
|         { |             return _data; | ||||||
|             return _data; |         } | ||||||
|         } |  | ||||||
|  |         const char* data() const | ||||||
|         const char* data() const |         { | ||||||
|         { |             return _data; | ||||||
|             return _data; |         } | ||||||
|         } |  | ||||||
|  |         size_t size() const | ||||||
|         size_t size() const |         { | ||||||
|         { |             return _size; | ||||||
|             return _size; |         } | ||||||
|         } |  | ||||||
|  |         inline const_iterator begin() const | ||||||
|         inline const_iterator begin() const |         { | ||||||
|         { |             return const_iterator(const_cast<char*>(_data)); | ||||||
|             return const_iterator(const_cast<char*>(_data)); |         } | ||||||
|         } |  | ||||||
|  |         inline const_iterator end() const | ||||||
|         inline const_iterator end() const |         { | ||||||
|         { |             return const_iterator(const_cast<char*>(_data) + _size); | ||||||
|             return const_iterator(const_cast<char*>(_data) + _size); |         } | ||||||
|         } |  | ||||||
|  |         inline const_iterator cbegin() const | ||||||
|         inline const_iterator cbegin() const |         { | ||||||
|         { |             return begin(); | ||||||
|             return begin(); |         } | ||||||
|         } |  | ||||||
|  |         inline const_iterator cend() const | ||||||
|         inline const_iterator cend() const |         { | ||||||
|         { |             return end(); | ||||||
|             return end(); |         } | ||||||
|         } |  | ||||||
|  |     private: | ||||||
|     private: |         const char* _data; | ||||||
|         const char* _data; |         const size_t _size; | ||||||
|         const size_t _size; |     }; | ||||||
|     }; |  | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -79,16 +79,7 @@ namespace ix | |||||||
|     void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket, |     void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket, | ||||||
|                                            std::shared_ptr<ConnectionState> connectionState) |                                            std::shared_ptr<ConnectionState> connectionState) | ||||||
|     { |     { | ||||||
|         handleUpgrade(std::move(socket), connectionState); |         setThreadName("WebSocketServer::" + connectionState->getId()); | ||||||
|  |  | ||||||
|         connectionState->setTerminated(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void WebSocketServer::handleUpgrade(std::unique_ptr<Socket> socket, |  | ||||||
|                                         std::shared_ptr<ConnectionState> connectionState, |  | ||||||
|                                         HttpRequestPtr request) |  | ||||||
|     { |  | ||||||
|         setThreadName("Srv:ws:" + connectionState->getId()); |  | ||||||
|  |  | ||||||
|         auto webSocket = std::make_shared<WebSocket>(); |         auto webSocket = std::make_shared<WebSocket>(); | ||||||
|         if (_onConnectionCallback) |         if (_onConnectionCallback) | ||||||
| @@ -98,7 +89,7 @@ namespace ix | |||||||
|             if (!webSocket->isOnMessageCallbackRegistered()) |             if (!webSocket->isOnMessageCallbackRegistered()) | ||||||
|             { |             { | ||||||
|                 logError("WebSocketServer Application developer error: Server callback improperly " |                 logError("WebSocketServer Application developer error: Server callback improperly " | ||||||
|                          "registered."); |                          "registerered."); | ||||||
|                 logError("Missing call to setOnMessageCallback inside setOnConnectionCallback."); |                 logError("Missing call to setOnMessageCallback inside setOnConnectionCallback."); | ||||||
|                 connectionState->setTerminated(); |                 connectionState->setTerminated(); | ||||||
|                 return; |                 return; | ||||||
| @@ -108,8 +99,9 @@ namespace ix | |||||||
|         { |         { | ||||||
|             WebSocket* webSocketRawPtr = webSocket.get(); |             WebSocket* webSocketRawPtr = webSocket.get(); | ||||||
|             webSocket->setOnMessageCallback( |             webSocket->setOnMessageCallback( | ||||||
|                 [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) |                 [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) { | ||||||
|                 { _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); }); |                     _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); | ||||||
|  |                 }); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
| @@ -138,7 +130,7 @@ namespace ix | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         auto status = webSocket->connectToSocket( |         auto status = webSocket->connectToSocket( | ||||||
|             std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate, request); |             std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate); | ||||||
|         if (status.success) |         if (status.success) | ||||||
|         { |         { | ||||||
|             // Process incoming messages and execute callbacks |             // Process incoming messages and execute callbacks | ||||||
| @@ -163,6 +155,8 @@ namespace ix | |||||||
|                 logError("Cannot delete client"); |                 logError("Cannot delete client"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         connectionState->setTerminated(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients() |     std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients() | ||||||
| @@ -182,30 +176,28 @@ 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(); | ||||||
|  |             if (msg->type == ix::WebSocketMessageType::Message) | ||||||
|             { |             { | ||||||
|                 auto remoteIp = connectionState->getRemoteIp(); |                 for (auto&& client : getClients()) | ||||||
|                 if (msg->type == ix::WebSocketMessageType::Message) |  | ||||||
|                 { |                 { | ||||||
|                     for (auto&& client : getClients()) |                     if (client.get() != &webSocket) | ||||||
|                     { |                     { | ||||||
|                         if (client.get() != &webSocket) |                         client->send(msg->str, msg->binary); | ||||||
|                         { |  | ||||||
|                             client->send(msg->str, msg->binary); |  | ||||||
|  |  | ||||||
|                             // Make sure the OS send buffer is flushed before moving on |                         // Make sure the OS send buffer is flushed before moving on | ||||||
|                             do |                         do | ||||||
|                             { |                         { | ||||||
|                                 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); | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }); |             } | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool WebSocketServer::listenAndStart() |     bool WebSocketServer::listenAndStart() | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ namespace ix | |||||||
|         int getHandshakeTimeoutSecs(); |         int getHandshakeTimeoutSecs(); | ||||||
|         bool isPongEnabled(); |         bool isPongEnabled(); | ||||||
|         bool isPerMessageDeflateEnabled(); |         bool isPerMessageDeflateEnabled(); | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         // Member variables |         // Member variables | ||||||
|         int _handshakeTimeoutSecs; |         int _handshakeTimeoutSecs; | ||||||
| @@ -74,10 +73,5 @@ namespace ix | |||||||
|         virtual void handleConnection(std::unique_ptr<Socket> socket, |         virtual void handleConnection(std::unique_ptr<Socket> socket, | ||||||
|                                       std::shared_ptr<ConnectionState> connectionState); |                                       std::shared_ptr<ConnectionState> connectionState); | ||||||
|         virtual size_t getConnectedClientsCount() final; |         virtual size_t getConnectedClientsCount() final; | ||||||
|  |  | ||||||
|     protected: |  | ||||||
|         void handleUpgrade(std::unique_ptr<Socket> socket, |  | ||||||
|                            std::shared_ptr<ConnectionState> connectionState, |  | ||||||
|                            HttpRequestPtr request = nullptr); |  | ||||||
|     }; |     }; | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ | |||||||
| #include <cstdarg> | #include <cstdarg> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|  | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| @@ -53,6 +54,7 @@ | |||||||
|  |  | ||||||
| namespace ix | namespace ix | ||||||
| { | { | ||||||
|  |     const std::string WebSocketTransport::kPingMessage("ixwebsocket::heartbeat"); | ||||||
|     const int WebSocketTransport::kDefaultPingIntervalSecs(-1); |     const int WebSocketTransport::kDefaultPingIntervalSecs(-1); | ||||||
|     const bool WebSocketTransport::kDefaultEnablePong(true); |     const bool WebSocketTransport::kDefaultEnablePong(true); | ||||||
|     const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300); |     const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300); | ||||||
| @@ -72,9 +74,6 @@ namespace ix | |||||||
|         , _enablePong(kDefaultEnablePong) |         , _enablePong(kDefaultEnablePong) | ||||||
|         , _pingIntervalSecs(kDefaultPingIntervalSecs) |         , _pingIntervalSecs(kDefaultPingIntervalSecs) | ||||||
|         , _pongReceived(false) |         , _pongReceived(false) | ||||||
|         , _setCustomMessage(false) |  | ||||||
|         , _kPingMessage("ixwebsocket::heartbeat") |  | ||||||
|         , _pingType(SendMessageKind::Ping) |  | ||||||
|         , _pingCount(0) |         , _pingCount(0) | ||||||
|         , _lastSendPingTimePoint(std::chrono::steady_clock::now()) |         , _lastSendPingTimePoint(std::chrono::steady_clock::now()) | ||||||
|     { |     { | ||||||
| @@ -140,7 +139,7 @@ namespace ix | |||||||
|                                                   _enablePerMessageDeflate); |                                                   _enablePerMessageDeflate); | ||||||
|  |  | ||||||
|             result = webSocketHandshake.clientHandshake( |             result = webSocketHandshake.clientHandshake( | ||||||
|                 remoteUrl, headers, protocol, host, path, port, timeoutSecs); |                 remoteUrl, headers, host, path, port, timeoutSecs); | ||||||
|  |  | ||||||
|             if (result.http_status >= 300 && result.http_status < 400) |             if (result.http_status >= 300 && result.http_status < 400) | ||||||
|             { |             { | ||||||
| @@ -171,8 +170,7 @@ 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, |                                                             bool enablePerMessageDeflate) | ||||||
|                                                             HttpRequestPtr request) |  | ||||||
|     { |     { | ||||||
|         std::lock_guard<std::mutex> lock(_socketMutex); |         std::lock_guard<std::mutex> lock(_socketMutex); | ||||||
|  |  | ||||||
| @@ -189,8 +187,7 @@ namespace ix | |||||||
|                                               _perMessageDeflateOptions, |                                               _perMessageDeflateOptions, | ||||||
|                                               _enablePerMessageDeflate); |                                               _enablePerMessageDeflate); | ||||||
|  |  | ||||||
|         auto result = |         auto result = webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate); | ||||||
|             webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate, request); |  | ||||||
|         if (result.success) |         if (result.success) | ||||||
|         { |         { | ||||||
|             setReadyState(ReadyState::OPEN); |             setReadyState(ReadyState::OPEN); | ||||||
| @@ -251,51 +248,13 @@ namespace ix | |||||||
|         return now - _lastSendPingTimePoint > std::chrono::seconds(_pingIntervalSecs); |         return now - _lastSendPingTimePoint > std::chrono::seconds(_pingIntervalSecs); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void WebSocketTransport::setPingMessage(const std::string& message, SendMessageKind pingType) |     WebSocketSendInfo WebSocketTransport::sendHeartBeat() | ||||||
|     { |  | ||||||
|         _setCustomMessage = true; |  | ||||||
|         _kPingMessage = message; |  | ||||||
|         _pingType = pingType; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     WebSocketSendInfo WebSocketTransport::sendHeartBeat(SendMessageKind pingMessage) |  | ||||||
|     { |     { | ||||||
|         _pongReceived = false; |         _pongReceived = false; | ||||||
|         std::stringstream ss; |         std::stringstream ss; | ||||||
|  |         ss << kPingMessage << "::" << _pingIntervalSecs << "s" | ||||||
|         ss << _kPingMessage; |            << "::" << _pingCount++; | ||||||
|         if (!_setCustomMessage) |         return sendPing(ss.str()); | ||||||
|         { |  | ||||||
|             ss << "::" << _pingIntervalSecs << "s" |  | ||||||
|                << "::" << _pingCount++; |  | ||||||
|         } |  | ||||||
|         if (pingMessage == SendMessageKind::Ping) |  | ||||||
|         { |  | ||||||
|             return sendPing(ss.str()); |  | ||||||
|         } |  | ||||||
|         else if (pingMessage == SendMessageKind::Binary) |  | ||||||
|         { |  | ||||||
|             WebSocketSendInfo info = sendBinary(ss.str(), nullptr); |  | ||||||
|             if (info.success) |  | ||||||
|             { |  | ||||||
|                 std::lock_guard<std::mutex> lck(_lastSendPingTimePointMutex); |  | ||||||
|                 _lastSendPingTimePoint = std::chrono::steady_clock::now(); |  | ||||||
|             } |  | ||||||
|             return info; |  | ||||||
|         } |  | ||||||
|         else if (pingMessage == SendMessageKind::Text) |  | ||||||
|         { |  | ||||||
|             WebSocketSendInfo info = sendText(ss.str(), nullptr); |  | ||||||
|             if (info.success) |  | ||||||
|             { |  | ||||||
|                 std::lock_guard<std::mutex> lck(_lastSendPingTimePointMutex); |  | ||||||
|                 _lastSendPingTimePoint = std::chrono::steady_clock::now(); |  | ||||||
|             } |  | ||||||
|             return info; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // unknow type ping message |  | ||||||
|         return {}; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool WebSocketTransport::closingDelayExceeded() |     bool WebSocketTransport::closingDelayExceeded() | ||||||
| @@ -311,9 +270,7 @@ namespace ix | |||||||
|         { |         { | ||||||
|             if (pingIntervalExceeded()) |             if (pingIntervalExceeded()) | ||||||
|             { |             { | ||||||
|                 // If it is not a 'ping' message of ping type, there is no need to judge whether |                 if (!_pongReceived) | ||||||
|                 // pong will receive it |  | ||||||
|                 if (_pingType == SendMessageKind::Ping && !_pongReceived) |  | ||||||
|                 { |                 { | ||||||
|                     // ping response (PONG) exceeds the maximum delay, close the connection |                     // ping response (PONG) exceeds the maximum delay, close the connection | ||||||
|                     close(WebSocketCloseConstants::kInternalErrorCode, |                     close(WebSocketCloseConstants::kInternalErrorCode, | ||||||
| @@ -321,7 +278,7 @@ namespace ix | |||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     sendHeartBeat(_pingType); |                     sendHeartBeat(); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -700,7 +657,6 @@ namespace ix | |||||||
|                 if (_readyState != ReadyState::CLOSING) |                 if (_readyState != ReadyState::CLOSING) | ||||||
|                 { |                 { | ||||||
|                     // send back the CLOSE frame |                     // send back the CLOSE frame | ||||||
|                     setReadyState(ReadyState::CLOSING); |  | ||||||
|                     sendCloseFrame(code, reason); |                     sendCloseFrame(code, reason); | ||||||
|  |  | ||||||
|                     wakeUpFromPoll(SelectInterrupt::kCloseRequest); |                     wakeUpFromPoll(SelectInterrupt::kCloseRequest); | ||||||
| @@ -1073,10 +1029,7 @@ namespace ix | |||||||
|             else if (ret <= 0) |             else if (ret <= 0) | ||||||
|             { |             { | ||||||
|                 closeSocket(); |                 closeSocket(); | ||||||
|                 if (_readyState != ReadyState::CLOSING) |                 setReadyState(ReadyState::CLOSED); | ||||||
|                 { |  | ||||||
|                     setReadyState(ReadyState::CLOSED); |  | ||||||
|                 } |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|   | |||||||
| @@ -18,10 +18,9 @@ | |||||||
| #include "IXWebSocketHttpHeaders.h" | #include "IXWebSocketHttpHeaders.h" | ||||||
| #include "IXWebSocketPerMessageDeflate.h" | #include "IXWebSocketPerMessageDeflate.h" | ||||||
| #include "IXWebSocketPerMessageDeflateOptions.h" | #include "IXWebSocketPerMessageDeflateOptions.h" | ||||||
| #include "IXWebSocketSendData.h" |  | ||||||
| #include "IXWebSocketSendInfo.h" | #include "IXWebSocketSendInfo.h" | ||||||
|  | #include "IXWebSocketSendData.h" | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstdint> |  | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <list> | #include <list> | ||||||
| #include <memory> | #include <memory> | ||||||
| @@ -87,8 +86,7 @@ namespace ix | |||||||
|         // Server |         // Server | ||||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, |         WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, | ||||||
|                                             int timeoutSecs, |                                             int timeoutSecs, | ||||||
|                                             bool enablePerMessageDeflate, |                                             bool enablePerMessageDeflate); | ||||||
|                                             HttpRequestPtr request = nullptr); |  | ||||||
|  |  | ||||||
|         PollResult poll(); |         PollResult poll(); | ||||||
|         WebSocketSendInfo sendBinary(const IXWebSocketSendData& message, |         WebSocketSendInfo sendBinary(const IXWebSocketSendData& message, | ||||||
| @@ -110,12 +108,8 @@ namespace ix | |||||||
|         void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback); |         void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback); | ||||||
|         size_t bufferedAmount() const; |         size_t bufferedAmount() const; | ||||||
|  |  | ||||||
|         // set ping heartbeat message |  | ||||||
|         void setPingMessage(const std::string& message, SendMessageKind pingType); |  | ||||||
|  |  | ||||||
|         // internal |         // internal | ||||||
|         // send any type of ping packet, not only 'ping' type |         WebSocketSendInfo sendHeartBeat(); | ||||||
|         WebSocketSendInfo sendHeartBeat(SendMessageKind pingType); |  | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         std::string _url; |         std::string _url; | ||||||
| @@ -220,10 +214,7 @@ namespace ix | |||||||
|         std::atomic<bool> _pongReceived; |         std::atomic<bool> _pongReceived; | ||||||
|  |  | ||||||
|         static const int kDefaultPingIntervalSecs; |         static const int kDefaultPingIntervalSecs; | ||||||
|  |         static const std::string kPingMessage; | ||||||
|         bool _setCustomMessage; |  | ||||||
|         std::string _kPingMessage; |  | ||||||
|         SendMessageKind _pingType; |  | ||||||
|         std::atomic<uint64_t> _pingCount; |         std::atomic<uint64_t> _pingCount; | ||||||
|  |  | ||||||
|         // We record when ping are being sent so that we can know when to send the next one |         // We record when ping are being sent so that we can know when to send the next one | ||||||
|   | |||||||
| @@ -6,4 +6,4 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #define IX_WEBSOCKET_VERSION "11.4.4" | #define IX_WEBSOCKET_VERSION "11.4.0" | ||||||
|   | |||||||
| @@ -13,24 +13,16 @@ all: brew | |||||||
|  |  | ||||||
| install: brew | install: brew | ||||||
|  |  | ||||||
| -DCMAKE_INSTALL_PREFIX=/opt/homebrew |  | ||||||
|  |  | ||||||
| # Use -DCMAKE_INSTALL_PREFIX= to install into another location | # Use -DCMAKE_INSTALL_PREFIX= to install into another location | ||||||
| # on osx it is good practice to make /usr/local user writable | # on osx it is good practice to make /usr/local user writable | ||||||
| # sudo chown -R `whoami`/staff /usr/local | # sudo chown -R `whoami`/staff /usr/local | ||||||
| # | # | ||||||
| # Those days (since Apple Silicon mac shipped), on macOS homebrew installs in /opt/homebrew, and /usr/local is readonly |  | ||||||
| # |  | ||||||
| # Release, Debug, MinSizeRel, RelWithDebInfo are the build types | # Release, Debug, MinSizeRel, RelWithDebInfo are the build types | ||||||
| # | # | ||||||
| # 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: | ||||||
| ifeq ($(shell uname),Darwin) |  | ||||||
| 	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_PREFIX=/opt/homebrew -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) |  | ||||||
| else |  | ||||||
| 	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) | 	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) | ||||||
| endif |  | ||||||
|  |  | ||||||
| # 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 | ||||||
|   | |||||||
| @@ -1,20 +0,0 @@ | |||||||
| -----BEGIN CERTIFICATE----- |  | ||||||
| MIIDNDCCAhwCFCl+O/rR8flqYKKvD0iwkucFwMaLMA0GCSqGSIb3DQEBCwUAMEEx |  | ||||||
| FDASBgNVBAoMC21hY2hpbmV6b25lMRQwEgYDVQQKDAtJWFdlYlNvY2tldDETMBEG |  | ||||||
| A1UEAwwKdHJ1c3RlZC1jYTAgFw0yMjA4MjMyMDM2MjVaGA80MjgxMDYwMTIwMzYy |  | ||||||
| NVowajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQHDAhCZXJrZWxl |  | ||||||
| eTEbMBkGA1UECgwSRHVtbXkgT3JnYW5pemF0aW9uMR4wHAYDVQQDDBVub3QuYS52 |  | ||||||
| YWxpZC5ob3N0Lm5hbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 |  | ||||||
| 9N806IjCvA82zfk9CPNwaEHOygNDJSXaZ38YDSI4C+Wf2imnMxrLQKaoccHUi+9L |  | ||||||
| 4rQN/hSCg+uTULQUZ0iyssGDaIh4IcAeoEcNlXYHTrgP+aAaby3q5zeZ80K3+6e4 |  | ||||||
| rqcuBPV2lLszJu3XXwEKbDSxW3De0gc2N8m9DN8Lx7i70DRf0F4m6RIMFF/kHXwa |  | ||||||
| zZLeG7rZb4xL684lmmQsWtk5Z600CvrBtUE7fQ7bhy0QhSt66kdTSL8IKQrbWcGj |  | ||||||
| q0tggFlOqeyZSi73gqUiAIuGO8/tRgmp4HygNyC24jpOB5nObOPPJTUEf5Mk1Bum |  | ||||||
| kD5a+yL6YbVdhiaK17wbAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKsLXGLfO1IZ |  | ||||||
| LbofGc7/TCQwRayR3RdG4864PBy97KfJWyizg7Wm4X4yPFRG+6q3X5NKW32Ew9lI |  | ||||||
| jXulXCTjWOiSxiG4Pk20uczkOhWVHFdnS9gZvykPC/ElxBKPalT6MMstZWxpElsk |  | ||||||
| rCDKXj4LkD0po8bZrjlgSZQQQk6XMRkoRai2GWLJqIjaNCSF8nqb1wM/1OE1tAwi |  | ||||||
| polO1eFMA24yypvlXcNrNXjqcQ7LaoQFQltmi/RV+uTk7EK2F2jgYVzJ/pe2ET0i |  | ||||||
| RIMbGZTlAiemDGL9SpMsxftG6fSmP6QqDqYExmmPlZMLprb2da/2kelWFA+VkvdG |  | ||||||
| zFrnIcyfMY4= |  | ||||||
| -----END CERTIFICATE----- |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| -----BEGIN RSA PRIVATE KEY----- |  | ||||||
| MIIEpAIBAAKCAQEAtvTfNOiIwrwPNs35PQjzcGhBzsoDQyUl2md/GA0iOAvln9op |  | ||||||
| pzMay0CmqHHB1IvvS+K0Df4UgoPrk1C0FGdIsrLBg2iIeCHAHqBHDZV2B064D/mg |  | ||||||
| Gm8t6uc3mfNCt/unuK6nLgT1dpS7Mybt118BCmw0sVtw3tIHNjfJvQzfC8e4u9A0 |  | ||||||
| X9BeJukSDBRf5B18Gs2S3hu62W+MS+vOJZpkLFrZOWetNAr6wbVBO30O24ctEIUr |  | ||||||
| eupHU0i/CCkK21nBo6tLYIBZTqnsmUou94KlIgCLhjvP7UYJqeB8oDcgtuI6TgeZ |  | ||||||
| zmzjzyU1BH+TJNQbppA+Wvsi+mG1XYYmite8GwIDAQABAoIBAGRzAXG9EglI01mV |  | ||||||
| sPfvyCi5NRhiFXRyGtxU4pTD8TuwXHxtfV0NU/KwJlBpVLBrvBCAAbeE/qHB6D9T |  | ||||||
| metx4ZorRs/tPrAmZ6LpANnWa50LfUdYGK0qyZ0lIYPm6YS2KJnfWm6LznEyq60j |  | ||||||
| /IW45YthaXTO7aOI0OjVrG+dd4CxU1g1NtCQ9bdDMDjfXFVnoOifXIl8W22eRMoZ |  | ||||||
| LzCz+0sI0R0LenXCPT566de21F0NDkIK7NaQ1l5BMX4PA+RsN3cZlzyruA1woPKI |  | ||||||
| aBR2LQGNrBfDVGMATtUm89RpWAftb8FmXqYUsM7zAzTO6dViitiB7OFlw7Ax15YH |  | ||||||
| MTj5zGECgYEA35ocEEMfyahBN70bjyiqOHlzKwFjDl9DsUf8xqHsNhYAL+GrOK9A |  | ||||||
| 8lN5ByzcnbV3TJtU4WYbPgQJld8gXFx4h3eS+SkA/ASkAdtgHfdMImZ1v7k3TIPf |  | ||||||
| DXOCsHzELsQY6OgiI572Nwzx/Tl+0dFwaOfLjU9iEmmqL667j1Y4NiMCgYEA0Xch |  | ||||||
| 9K/vwZ1I9gM3ySvG40R2TRriC9Bf8jwrEWeRsWNvBcqtMMrgwAMsMCKDugSZR7n6 |  | ||||||
| o3WZV6mpvYVLFx0b93v07i7EpFP27kMw3gLNBKX62snR9JbqwAMK7tktgLds5pKM |  | ||||||
| DvLHuAQ9XMMXMLX7WlSyhmtFeU7IDulTSHHqdakCgYEAywITCpy2xpKRK7bwx4gH |  | ||||||
| C6EQc/IdahYJ0nHmSL0IRY6x+sbrelp7H8ezcVVEs5bmylGYvc/DWgm2XjCnI9P8 |  | ||||||
| xhlFAhw9PZJFCT6QRISaxfy6WSgi0cBEieTeubd9MmxtpT/khuyy5AZHyj0iLAL4 |  | ||||||
| CPayMwjopIj0r7f3p8qC3HsCgYBmq2kmYVI4aZrIkv02CtIatYTy+DlSJxnQRvOp |  | ||||||
| PUWpWB6kDRrk7pxJIYT4NwKwG+7xvFQA6PR3hn7fmUUcGDWMEeMVGDFkho9ja+W4 |  | ||||||
| /FB3dc/Gi+PwakS4RwWF20e1brLfNXeXICMKrHFTVYC5bIm+VgOHZW8RLa9bt7wN |  | ||||||
| p2CPuQKBgQCjW+rCODmMzEues/I143mYMDdZ1IschtWGiXBNrpkHm/DcZSutbacm |  | ||||||
| 5C7Kwv44pfA90NHDTjuaIgRgfeUTawkrl8uPXEuj80mW72agf5oS8lJzD+2jibCj |  | ||||||
| Q4K52G+0LaTxHLZxufil28Rgja01c0mTcuLbhKtCgHl5EHP19wOKEg== |  | ||||||
| -----END RSA PRIVATE KEY----- |  | ||||||
| @@ -16,7 +16,7 @@ set (TEST_TARGET_NAMES | |||||||
|   IXWebSocketServerTest |   IXWebSocketServerTest | ||||||
|   IXWebSocketTestConnectionDisconnection |   IXWebSocketTestConnectionDisconnection | ||||||
|   IXUrlParserTest |   IXUrlParserTest | ||||||
|   # IXHttpClientTest ## FIXME httpbin.org does not seem normal |   IXHttpClientTest | ||||||
|   IXUnityBuildsTest |   IXUnityBuildsTest | ||||||
|   IXHttpTest |   IXHttpTest | ||||||
|   IXDNSLookupTest |   IXDNSLookupTest | ||||||
| @@ -24,13 +24,14 @@ set (TEST_TARGET_NAMES | |||||||
|   # IXWebSocketBroadcastTest ## FIXME was depending on cobra / take a broadcast server from ws |   # IXWebSocketBroadcastTest ## FIXME was depending on cobra / take a broadcast server from ws | ||||||
|   IXStrCaseCompareTest |   IXStrCaseCompareTest | ||||||
|   IXExponentialBackoffTest |   IXExponentialBackoffTest | ||||||
|   IXWebSocketCloseTest |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| # Some unittest don't work on windows yet | # Some unittest don't work on windows yet | ||||||
| # Windows without TLS does not have hmac yet | # Windows without TLS does not have hmac yet | ||||||
| if (UNIX) | if (UNIX) | ||||||
|   list(APPEND TEST_TARGET_NAMES |   list(APPEND TEST_TARGET_NAMES | ||||||
|  |     IXWebSocketCloseTest | ||||||
|  |  | ||||||
|     # Fail on Windows in CI probably because the pathing is wrong and |     # Fail on Windows in CI probably because the pathing is wrong and | ||||||
|     # some resource files cannot be found |     # some resource files cannot be found | ||||||
|     IXHttpServerTest |     IXHttpServerTest | ||||||
|   | |||||||
| @@ -19,9 +19,13 @@ TEST_CASE("dns", "[net]") | |||||||
|         auto dnsLookup = std::make_shared<DNSLookup>("www.google.com", 80); |         auto dnsLookup = std::make_shared<DNSLookup>("www.google.com", 80); | ||||||
|  |  | ||||||
|         std::string errMsg; |         std::string errMsg; | ||||||
|         auto res = dnsLookup->resolve(errMsg, [] { return false; }); |         struct addrinfo* res; | ||||||
|  |  | ||||||
|  |         res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||||
|         std::cerr << "Error message: " << errMsg << std::endl; |         std::cerr << "Error message: " << errMsg << std::endl; | ||||||
|         REQUIRE(res != nullptr); |         REQUIRE(res != nullptr); | ||||||
|  |  | ||||||
|  |         dnsLookup->release(res); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     SECTION("Test resolving a non-existing hostname") |     SECTION("Test resolving a non-existing hostname") | ||||||
| @@ -29,7 +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; | ||||||
|         auto res = dnsLookup->resolve(errMsg, [] { return false; }); |         struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||||
|         std::cerr << "Error message: " << errMsg << std::endl; |         std::cerr << "Error message: " << errMsg << std::endl; | ||||||
|         REQUIRE(res == nullptr); |         REQUIRE(res == nullptr); | ||||||
|     } |     } | ||||||
| @@ -40,7 +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 | ||||||
|         auto res = dnsLookup->resolve(errMsg, [] { return true; }); |         struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; }); | ||||||
|         std::cerr << "Error message: " << errMsg << std::endl; |         std::cerr << "Error message: " << errMsg << std::endl; | ||||||
|         REQUIRE(res == nullptr); |         REQUIRE(res == nullptr); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -7,9 +7,7 @@ | |||||||
| #include "catch.hpp" | #include "catch.hpp" | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <ixwebsocket/IXGetFreePort.h> |  | ||||||
| #include <ixwebsocket/IXHttpClient.h> | #include <ixwebsocket/IXHttpClient.h> | ||||||
| #include <ixwebsocket/IXHttpServer.h> |  | ||||||
|  |  | ||||||
| using namespace ix; | using namespace ix; | ||||||
|  |  | ||||||
| @@ -97,52 +95,6 @@ TEST_CASE("http_client", "[http]") | |||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(IXWEBSOCKET_USE_TLS) && !defined(IXWEBSOCKET_USE_SECURE_TRANSPORT) |  | ||||||
|     SECTION("Disable hostname validation") |  | ||||||
|     { |  | ||||||
|         static auto test_cert_with_wrong_name = [](bool validate_hostname) |  | ||||||
|         { |  | ||||||
|             int port = getFreePort(); |  | ||||||
|             ix::HttpServer server(port, "127.0.0.1"); |  | ||||||
|  |  | ||||||
|             SocketTLSOptions tlsOptionsServer; |  | ||||||
|             tlsOptionsServer.tls = true; |  | ||||||
|             tlsOptionsServer.caFile = "NONE"; |  | ||||||
|             tlsOptionsServer.certFile = "./.certs/wrong-name-server-crt.pem"; |  | ||||||
|             tlsOptionsServer.keyFile = "./.certs/wrong-name-server-key.pem"; |  | ||||||
|             server.setTLSOptions(tlsOptionsServer); |  | ||||||
|  |  | ||||||
|             auto res = server.listen(); |  | ||||||
|             REQUIRE(res.first); |  | ||||||
|             server.start(); |  | ||||||
|  |  | ||||||
|             HttpClient httpClient; |  | ||||||
|             SocketTLSOptions tlsOptionsClient; |  | ||||||
|             tlsOptionsClient.caFile = "./.certs/trusted-ca-crt.pem"; |  | ||||||
|             tlsOptionsClient.disable_hostname_validation = validate_hostname; |  | ||||||
|             httpClient.setTLSOptions(tlsOptionsClient); |  | ||||||
|  |  | ||||||
|             std::string url("https://localhost:" + std::to_string(port)); |  | ||||||
|             auto args = httpClient.createRequest(url); |  | ||||||
|             args->connectTimeout = 10; |  | ||||||
|             args->transferTimeout = 10; |  | ||||||
|  |  | ||||||
|             auto response = httpClient.get(url, args); |  | ||||||
|  |  | ||||||
|             std::cerr << "Status: " << response->statusCode << std::endl; |  | ||||||
|             std::cerr << "Error code: " << (int) response->errorCode << std::endl; |  | ||||||
|             std::cerr << "Error message: " << response->errorMsg << std::endl; |  | ||||||
|  |  | ||||||
|             server.stop(); |  | ||||||
|             return std::make_tuple(response->errorCode, response->statusCode); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         REQUIRE(test_cert_with_wrong_name(false) == |  | ||||||
|                 std::make_tuple(HttpErrorCode::CannotConnect, 0)); |  | ||||||
|         REQUIRE(test_cert_with_wrong_name(true) == std::make_tuple(HttpErrorCode::Ok, 404)); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     SECTION("Async API, one call") |     SECTION("Async API, one call") | ||||||
|     { |     { | ||||||
|         bool async = true; |         bool async = true; | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -77,6 +77,24 @@ namespace | |||||||
|         return std::make_pair(res.first, std::string(vec.begin(), vec.end())); |         return std::make_pair(res.first, std::string(vec.begin(), vec.end())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Assume the file exists | ||||||
|  |     std::string readBytes(const std::string& path) | ||||||
|  |     { | ||||||
|  |         std::vector<uint8_t> memblock; | ||||||
|  |         std::ifstream file(path); | ||||||
|  |  | ||||||
|  |         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>()); | ||||||
|  |  | ||||||
|  |         std::string bytes(memblock.begin(), memblock.end()); | ||||||
|  |         return bytes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     std::string truncate(const std::string& str, size_t n) |     std::string truncate(const std::string& str, size_t n) | ||||||
|     { |     { | ||||||
|         if (str.size() < n) |         if (str.size() < n) | ||||||
| @@ -89,6 +107,12 @@ namespace | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     bool fileExists(const std::string& fileName) | ||||||
|  |     { | ||||||
|  |         std::ifstream infile(fileName); | ||||||
|  |         return infile.good(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     std::string extractFilename(const std::string& path) |     std::string extractFilename(const std::string& path) | ||||||
|     { |     { | ||||||
|         std::string::size_type idx; |         std::string::size_type idx; | ||||||
| @@ -892,8 +916,9 @@ namespace ix | |||||||
|         auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80); |         auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80); | ||||||
|  |  | ||||||
|         std::string errMsg; |         std::string errMsg; | ||||||
|  |         struct addrinfo* res; | ||||||
|  |  | ||||||
|         auto res = dnsLookup->resolve(errMsg, [] { return false; }); |         res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||||
|  |  | ||||||
|         auto addr = res->ai_addr; |         auto addr = res->ai_addr; | ||||||
|  |  | ||||||
| @@ -2461,8 +2486,10 @@ int main(int argc, char** argv) | |||||||
|     bool verbose = false; |     bool verbose = false; | ||||||
|     bool save = false; |     bool save = false; | ||||||
|     bool quiet = false; |     bool quiet = false; | ||||||
|  |     bool fluentd = false; | ||||||
|     bool compress = false; |     bool compress = false; | ||||||
|     bool compressRequest = false; |     bool compressRequest = false; | ||||||
|  |     bool stress = false; | ||||||
|     bool disableAutomaticReconnection = false; |     bool disableAutomaticReconnection = false; | ||||||
|     bool disablePerMessageDeflate = false; |     bool disablePerMessageDeflate = false; | ||||||
|     bool greetings = false; |     bool greetings = false; | ||||||
| @@ -2478,6 +2505,7 @@ int main(int argc, char** argv) | |||||||
|     int transferTimeout = 1800; |     int transferTimeout = 1800; | ||||||
|     int maxRedirects = 5; |     int maxRedirects = 5; | ||||||
|     int delayMs = -1; |     int delayMs = -1; | ||||||
|  |     int count = 1; | ||||||
|     int msgCount = 1000 * 1000; |     int msgCount = 1000 * 1000; | ||||||
|     uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds |     uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds | ||||||
|     int pingIntervalSecs = 30; |     int pingIntervalSecs = 30; | ||||||
| @@ -2501,7 +2529,6 @@ int main(int argc, char** argv) | |||||||
|                         "A (comma/space/colon) separated list of ciphers to use for TLS"); |                         "A (comma/space/colon) separated list of ciphers to use for TLS"); | ||||||
|         app->add_flag("--tls", tlsOptions.tls, "Enable TLS (server only)"); |         app->add_flag("--tls", tlsOptions.tls, "Enable TLS (server only)"); | ||||||
|         app->add_flag("--verify_none", verifyNone, "Disable peer cert verification"); |         app->add_flag("--verify_none", verifyNone, "Disable peer cert verification"); | ||||||
|         app->add_flag("--disable-hostname-validation", tlsOptions.disable_hostname_validation, "Disable validation of certificates' hostnames"); |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     app.add_flag("--version", version, "Print ws version"); |     app.add_flag("--version", version, "Print ws version"); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user