Compare commits
	
		
			6 Commits
		
	
	
		
			bug/docker
			...
			feature/ci
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 84163ad19e | ||
|  | 5e5b7c34ca | ||
|  | 9bb1de64a4 | ||
|  | df9889947d | ||
|  | 6ede8c85b0 | ||
|  | 2663f605f4 | 
							
								
								
									
										2
									
								
								.github/workflows/unittest_linux.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_linux.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ name: linux | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     paths-ignore: |     paths-ignore: | ||||||
|     - 'docs/**' |     - './**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   linux: |   linux: | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_linux_asan.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_linux_asan.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ name: linux_asan | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     paths-ignore: |     paths-ignore: | ||||||
|     - 'docs/**' |     - './**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   linux: |   linux: | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ name: mac_tsan_mbedtls | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     paths-ignore: |     paths-ignore: | ||||||
|     - 'docs/**' |     - './**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   mac_tsan_mbedtls: |   mac_tsan_mbedtls: | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ name: mac_tsan_openssl | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     paths-ignore: |     paths-ignore: | ||||||
|     - 'docs/**' |     - './**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   mac_tsan_openssl: |   mac_tsan_openssl: | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ name: mac_tsan_sectransport | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     paths-ignore: |     paths-ignore: | ||||||
|     - 'docs/**' |     - './**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   mac_tsan_sectransport: |   mac_tsan_sectransport: | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/unittest_uwp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/unittest_uwp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ name: uwp | |||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     paths-ignore: |     paths-ignore: | ||||||
|     - 'docs/**' |     - './**' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   uwp: |   uwp: | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") | |||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if (UNIX) | if (UNIX) | ||||||
|   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -gz") |   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") | ||||||
|   | |||||||
| @@ -77,8 +77,6 @@ IXWebSocket is actively being developed, check out the [changelog](https://machi | |||||||
|  |  | ||||||
| IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/autobahn/reports/clients/index.html). Some tests are still failing in the server code. | IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version. See the current [test results](https://bsergean.github.io/autobahn/reports/clients/index.html). Some tests are still failing in the server code. | ||||||
|  |  | ||||||
| Starting with the 11.0.8 release, IXWebSocket should be fully C++11 compatible. |  | ||||||
|  |  | ||||||
| ## Users | ## Users | ||||||
|  |  | ||||||
| If your company or project is using this library, feel free to open an issue or PR to amend this list. | If your company or project is using this library, feel free to open an issue or PR to amend this list. | ||||||
| @@ -115,10 +113,6 @@ To check the performance of a websocket library, you can look at the [autoroute] | |||||||
| | UWP               | Disabled          | None              | [![Build2][6]][0] | | | UWP               | Disabled          | None              | [![Build2][6]][0] | | ||||||
| | Linux             | OpenSSL           | Address Sanitizer | [![Build2][7]][0] | | | Linux             | OpenSSL           | Address Sanitizer | [![Build2][7]][0] | | ||||||
|  |  | ||||||
| * ASAN fails on Linux because of a known problem, we need a  |  | ||||||
| * Some tests are disabled on Windows/UWP because of a pathing problem |  | ||||||
| * TLS and ZLIB are disabled on Windows/UWP because enabling make the CI run takes a lot of time, for setting up vcpkg. |  | ||||||
|  |  | ||||||
| [0]: https://github.com/machinezone/IXWebSocket | [0]: https://github.com/machinezone/IXWebSocket | ||||||
| [1]: https://github.com/machinezone/IXWebSocket/workflows/linux/badge.svg | [1]: https://github.com/machinezone/IXWebSocket/workflows/linux/badge.svg | ||||||
| [2]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_sectransport/badge.svg | [2]: https://github.com/machinezone/IXWebSocket/workflows/mac_tsan_sectransport/badge.svg | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								build.sh
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								build.sh
									
									
									
									
									
								
							| @@ -1,7 +0,0 @@ | |||||||
| #!/bin/sh |  | ||||||
|  |  | ||||||
| rm -rf build |  | ||||||
| mkdir -p build  |  | ||||||
| cd build  |  | ||||||
| cmake -GNinja -DCMAKE_UNITY_BUILD=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=OFF ..  |  | ||||||
| ninja |  | ||||||
| @@ -1,25 +1,39 @@ | |||||||
| # Build time | FROM alpine:3.12 as build | ||||||
| # |  | ||||||
| # Build with |  | ||||||
| # docker build --ssh default -t ws . |  | ||||||
| # |  | ||||||
| # focal == ubuntu 2020.04 |  | ||||||
| # groovy == ubuntu 2020.10 |  | ||||||
| FROM ubuntu:groovy |  | ||||||
|  |  | ||||||
| RUN apt update | RUN apk add --no-cache \ | ||||||
|  |     gcc g++ musl-dev linux-headers \ | ||||||
|  |     cmake mbedtls-dev make zlib-dev python3-dev ninja git | ||||||
|  |  | ||||||
| RUN apt-get -y install g++ cmake make automake ccache libtool flex bison pkg-config git python3 jq | RUN addgroup -S app && \ | ||||||
| RUN apt-get -y install libjemalloc-dev libssl-dev libmcrypt-dev mcrypt zlib1g lua5.1-dev uuid-dev libz-dev binutils-dev |     adduser -S -G app app && \ | ||||||
| RUN apt-get -y install libboost-dev libboost-test-dev libboost-program-options-dev libboost-all-dev libboost-regex-dev  |     chown -R app:app /opt && \ | ||||||
| RUN apt-get -y install ninja-build |     chown -R app:app /usr/local | ||||||
|  |  | ||||||
| COPY . /opt | # There is a bug in CMake where we cannot build from the root top folder | ||||||
|  | # So we build from /opt | ||||||
|  | COPY --chown=app:app . /opt | ||||||
| WORKDIR /opt | WORKDIR /opt | ||||||
|  |  | ||||||
| RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts | USER app | ||||||
| RUN rm -rf build | RUN make -f makefile.dev ws_mbedtls_install && \ | ||||||
| RUN --mount=type=ssh ./build.sh |     sh tools/trim_repo_for_docker.sh | ||||||
|  |  | ||||||
| COPY /opt/build/ws/ws /usr/local/bin/ws | FROM alpine:3.12 as runtime | ||||||
| CMD ["/usr/local/bin/ws"] |  | ||||||
|  | RUN apk add --no-cache libstdc++ mbedtls ca-certificates python3 strace && \ | ||||||
|  |     addgroup -S app && \ | ||||||
|  |     adduser -S -G app app | ||||||
|  |  | ||||||
|  | COPY --chown=app:app --from=build /usr/local/bin/ws /usr/local/bin/ws | ||||||
|  |  | ||||||
|  | # COPY --chown=app:app --from=build /opt /opt | ||||||
|  |  | ||||||
|  | RUN chmod +x /usr/local/bin/ws && \ | ||||||
|  |     ldd /usr/local/bin/ws | ||||||
|  |  | ||||||
|  | # Now run in usermode | ||||||
|  | USER app | ||||||
|  | WORKDIR /home/app | ||||||
|  |  | ||||||
|  | ENTRYPOINT ["ws"] | ||||||
|  | EXPOSE 8008 | ||||||
|   | |||||||
| @@ -97,10 +97,9 @@ namespace ix | |||||||
|         } |         } | ||||||
|         else if (_onClientMessageCallback) |         else if (_onClientMessageCallback) | ||||||
|         { |         { | ||||||
|             WebSocket* webSocketRawPtr = webSocket.get(); |  | ||||||
|             webSocket->setOnMessageCallback( |             webSocket->setOnMessageCallback( | ||||||
|                 [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) { |                 [this, &ws = *webSocket.get(), connectionState](const WebSocketMessagePtr& msg) { | ||||||
|                     _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); |                     _onClientMessageCallback(connectionState, ws, msg); | ||||||
|                 }); |                 }); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
| @@ -169,46 +168,4 @@ namespace ix | |||||||
|         std::lock_guard<std::mutex> lock(_clientsMutex); |         std::lock_guard<std::mutex> lock(_clientsMutex); | ||||||
|         return _clients.size(); |         return _clients.size(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // |  | ||||||
|     // Classic servers |  | ||||||
|     // |  | ||||||
|     void WebSocketServer::makeBroadcastServer() |  | ||||||
|     { |  | ||||||
|         setOnClientMessageCallback( |  | ||||||
|             [this](std::shared_ptr<ConnectionState> connectionState, |  | ||||||
|                    WebSocket& webSocket, |  | ||||||
|                    const WebSocketMessagePtr& msg) { |  | ||||||
|                 auto remoteIp = connectionState->getRemoteIp(); |  | ||||||
|                 if (msg->type == ix::WebSocketMessageType::Message) |  | ||||||
|                 { |  | ||||||
|                     for (auto&& client : getClients()) |  | ||||||
|                     { |  | ||||||
|                         if (client.get() != &webSocket) |  | ||||||
|                         { |  | ||||||
|                             client->send(msg->str, msg->binary); |  | ||||||
|  |  | ||||||
|                             // Make sure the OS send buffer is flushed before moving on |  | ||||||
|                             do |  | ||||||
|                             { |  | ||||||
|                                 size_t bufferedAmount = client->bufferedAmount(); |  | ||||||
|                                 std::chrono::duration<double, std::milli> duration(500); |  | ||||||
|                                 std::this_thread::sleep_for(duration); |  | ||||||
|                             } while (client->bufferedAmount() != 0); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     int WebSocketServer::listenAndStart() |  | ||||||
|     { |  | ||||||
|         auto res = listen(); |  | ||||||
|         if (!res.first) |  | ||||||
|         { |  | ||||||
|             return 1; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         start(); |  | ||||||
|     } |  | ||||||
| } // namespace ix | } // namespace ix | ||||||
|   | |||||||
| @@ -47,9 +47,6 @@ namespace ix | |||||||
|         // Get all the connected clients |         // Get all the connected clients | ||||||
|         std::set<std::shared_ptr<WebSocket>> getClients(); |         std::set<std::shared_ptr<WebSocket>> getClients(); | ||||||
|  |  | ||||||
|         void makeBroadcastServer(); |  | ||||||
|         int listenAndStart(); |  | ||||||
|  |  | ||||||
|         const static int kDefaultHandShakeTimeoutSecs; |         const static int kDefaultHandShakeTimeoutSecs; | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ namespace ix | |||||||
|  |  | ||||||
|             // Comparison should be case insensitive |             // Comparison should be case insensitive | ||||||
|             REQUIRE(httpHeaders["Foo"] == "foo"); |             REQUIRE(httpHeaders["Foo"] == "foo"); | ||||||
|             REQUIRE(httpHeaders["Foo"] != "bar"); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SECTION("2") |         SECTION("2") | ||||||
| @@ -40,7 +39,7 @@ namespace ix | |||||||
|  |  | ||||||
|             headers["Upgrade"] = "webSocket"; |             headers["Upgrade"] = "webSocket"; | ||||||
|  |  | ||||||
|             REQUIRE(!CaseInsensitiveLess::cmp(headers["upGRADE"], "webSocket")); |             REQUIRE(CaseInsensitiveLess::cmp(headers["upgrade"], "WebSocket") == 0); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										102
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -439,6 +439,93 @@ namespace ix | |||||||
|         return generateReport(url) ? 0 : 1; |         return generateReport(url) ? 0 : 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // | ||||||
|  |     //  broadcast server | ||||||
|  |     // | ||||||
|  |     int ws_broadcast_server_main(int port, | ||||||
|  |                                  const std::string& hostname, | ||||||
|  |                                  const ix::SocketTLSOptions& tlsOptions) | ||||||
|  |     { | ||||||
|  |         spdlog::info("Listening on {}:{}", hostname, port); | ||||||
|  |  | ||||||
|  |         ix::WebSocketServer server(port, hostname); | ||||||
|  |         server.setTLSOptions(tlsOptions); | ||||||
|  |  | ||||||
|  |         server.setOnClientMessageCallback( | ||||||
|  |             [&server](std::shared_ptr<ConnectionState> connectionState, | ||||||
|  |                       WebSocket& webSocket, | ||||||
|  |                       const WebSocketMessagePtr& msg) { | ||||||
|  |                 auto remoteIp = connectionState->getRemoteIp(); | ||||||
|  |                 if (msg->type == ix::WebSocketMessageType::Open) | ||||||
|  |                 { | ||||||
|  |                     spdlog::info("New connection"); | ||||||
|  |                     spdlog::info("remote ip: {}", remoteIp); | ||||||
|  |                     spdlog::info("id: {}", connectionState->getId()); | ||||||
|  |                     spdlog::info("Uri: {}", msg->openInfo.uri); | ||||||
|  |                     spdlog::info("Headers:"); | ||||||
|  |                     for (auto it : msg->openInfo.headers) | ||||||
|  |                     { | ||||||
|  |                         spdlog::info("{}: {}", it.first, it.second); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 else if (msg->type == ix::WebSocketMessageType::Close) | ||||||
|  |                 { | ||||||
|  |                     spdlog::info("Closed connection: code {} reason {}", | ||||||
|  |                                  msg->closeInfo.code, | ||||||
|  |                                  msg->closeInfo.reason); | ||||||
|  |                 } | ||||||
|  |                 else if (msg->type == ix::WebSocketMessageType::Error) | ||||||
|  |                 { | ||||||
|  |                     std::stringstream ss; | ||||||
|  |                     ss << "Connection error: " << msg->errorInfo.reason << std::endl; | ||||||
|  |                     ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||||
|  |                     ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||||
|  |                     ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||||
|  |                     spdlog::info(ss.str()); | ||||||
|  |                 } | ||||||
|  |                 else if (msg->type == ix::WebSocketMessageType::Fragment) | ||||||
|  |                 { | ||||||
|  |                     spdlog::info("Received message fragment"); | ||||||
|  |                 } | ||||||
|  |                 else if (msg->type == ix::WebSocketMessageType::Message) | ||||||
|  |                 { | ||||||
|  |                     spdlog::info("Received {} bytes", msg->wireSize); | ||||||
|  |  | ||||||
|  |                     for (auto&& client : server.getClients()) | ||||||
|  |                     { | ||||||
|  |                         if (client.get() != &webSocket) | ||||||
|  |                         { | ||||||
|  |                             client->send(msg->str, msg->binary, [](int current, int total) -> bool { | ||||||
|  |                                 spdlog::info("Step {} out of {}", current, total); | ||||||
|  |                                 return true; | ||||||
|  |                             }); | ||||||
|  |  | ||||||
|  |                             do | ||||||
|  |                             { | ||||||
|  |                                 size_t bufferedAmount = client->bufferedAmount(); | ||||||
|  |                                 spdlog::info("{} bytes left to be sent", bufferedAmount); | ||||||
|  |  | ||||||
|  |                                 std::chrono::duration<double, std::milli> duration(500); | ||||||
|  |                                 std::this_thread::sleep_for(duration); | ||||||
|  |                             } while (client->bufferedAmount() != 0); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |         auto res = server.listen(); | ||||||
|  |         if (!res.first) | ||||||
|  |         { | ||||||
|  |             spdlog::info(res.second); | ||||||
|  |             return 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         server.start(); | ||||||
|  |         server.wait(); | ||||||
|  |  | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      *  ws_chat.cpp |      *  ws_chat.cpp | ||||||
|      *  Author: Benjamin Sergeant |      *  Author: Benjamin Sergeant | ||||||
| @@ -901,9 +988,6 @@ namespace ix | |||||||
|  |  | ||||||
|         auto addr = res->ai_addr; |         auto addr = res->ai_addr; | ||||||
|  |  | ||||||
|         // FIXME: this display weird addresses / we could steal libuv inet.c |  | ||||||
|         // code which display correct results |  | ||||||
|  |  | ||||||
|         char str[INET_ADDRSTRLEN]; |         char str[INET_ADDRSTRLEN]; | ||||||
|         inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN); |         inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN); | ||||||
|  |  | ||||||
| @@ -2769,13 +2853,9 @@ int main(int argc, char** argv) | |||||||
|         ret = ix::ws_push_server( |         ret = ix::ws_push_server( | ||||||
|             port, hostname, tlsOptions, ipv6, disablePerMessageDeflate, disablePong, sendMsg); |             port, hostname, tlsOptions, ipv6, disablePerMessageDeflate, disablePong, sendMsg); | ||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("transfer") || app.got_subcommand("broadcast_server")) |     else if (app.got_subcommand("transfer")) | ||||||
|     { |     { | ||||||
|         ix::WebSocketServer server(port, hostname); |         ret = ix::ws_transfer_main(port, hostname, tlsOptions); | ||||||
|         server.setTLSOptions(tlsOptions); |  | ||||||
|         server.makeBroadcastServer(); |  | ||||||
|         server.listenAndStart(); |  | ||||||
|         server.wait(); |  | ||||||
|     } |     } | ||||||
|     else if (app.got_subcommand("send")) |     else if (app.got_subcommand("send")) | ||||||
|     { |     { | ||||||
| @@ -2790,6 +2870,10 @@ int main(int argc, char** argv) | |||||||
|     { |     { | ||||||
|         ret = ix::ws_chat_main(url, user); |         ret = ix::ws_chat_main(url, user); | ||||||
|     } |     } | ||||||
|  |     else if (app.got_subcommand("broadcast_server")) | ||||||
|  |     { | ||||||
|  |         ret = ix::ws_broadcast_server_main(port, hostname, tlsOptions); | ||||||
|  |     } | ||||||
|     else if (app.got_subcommand("ping")) |     else if (app.got_subcommand("ping")) | ||||||
|     { |     { | ||||||
|         ret = ix::ws_ping_pong_main(url, tlsOptions); |         ret = ix::ws_ping_pong_main(url, tlsOptions); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user