├── .gitattributes ├── .github └── workflows │ ├── build-linux-clang.yml │ ├── build-linux-gcc.yml │ ├── build-macos.yml │ ├── build-windows-mingw.yml │ ├── build-windows-msys2.yml │ ├── build-windows-vs.yml │ └── doxygen.yml ├── .gitignore ├── .gitlinks ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TODO.md ├── bin └── .gitignore ├── documents └── Doxyfile ├── examples ├── asio_service.cpp ├── asio_service.h ├── asio_timer.cpp ├── http_client.cpp ├── http_server.cpp ├── https_client.cpp ├── https_server.cpp ├── proto_client.cpp ├── proto_server.cpp ├── ssl_chat_client.cpp ├── ssl_chat_server.cpp ├── tcp_chat_client.cpp ├── tcp_chat_server.cpp ├── udp_echo_client.cpp ├── udp_echo_server.cpp ├── udp_multicast_client.cpp ├── udp_multicast_server.cpp ├── ws_chat_client.cpp ├── ws_chat_server.cpp ├── wss_chat_client.cpp └── wss_chat_server.cpp ├── images ├── multicast.ai ├── multicast.png ├── openapi-http.png ├── openapi-https.png ├── round-trip.ai ├── round-trip.png ├── ws-chat.png └── wss-chat.png ├── include └── server │ ├── asio │ ├── asio.h │ ├── asio.inl │ ├── memory.h │ ├── memory.inl │ ├── service.h │ ├── ssl_client.h │ ├── ssl_context.h │ ├── ssl_server.h │ ├── ssl_session.h │ ├── tcp_client.h │ ├── tcp_resolver.h │ ├── tcp_server.h │ ├── tcp_session.h │ ├── timer.h │ ├── udp_client.h │ ├── udp_resolver.h │ └── udp_server.h │ ├── http │ ├── http.h │ ├── http_client.h │ ├── http_request.h │ ├── http_request.inl │ ├── http_response.h │ ├── http_response.inl │ ├── http_server.h │ ├── http_session.h │ ├── https_client.h │ ├── https_server.h │ └── https_session.h │ ├── version.h │ └── ws │ ├── ws.h │ ├── ws_client.h │ ├── ws_server.h │ ├── ws_session.h │ ├── wss_client.h │ ├── wss_server.h │ └── wss_session.h ├── modules ├── CMakeLists.txt ├── Catch2.cmake ├── CppBenchmark.cmake ├── CppCommon.cmake ├── asio.cmake └── cpp-optparse.cmake ├── performance ├── http_trace_client.cpp ├── http_trace_server.cpp ├── https_trace_client.cpp ├── https_trace_server.cpp ├── proto_client.cpp ├── proto_server.cpp ├── ssl_echo_client.cpp ├── ssl_echo_server.cpp ├── ssl_multicast_client.cpp ├── ssl_multicast_server.cpp ├── tcp_echo_client.cpp ├── tcp_echo_server.cpp ├── tcp_multicast_client.cpp ├── tcp_multicast_server.cpp ├── udp_echo_client.cpp ├── udp_echo_server.cpp ├── udp_multicast_client.cpp ├── udp_multicast_server.cpp ├── ws_echo_client.cpp ├── ws_echo_server.cpp ├── ws_multicast_client.cpp ├── ws_multicast_server.cpp ├── wss_echo_client.cpp ├── wss_echo_server.cpp ├── wss_multicast_client.cpp └── wss_multicast_server.cpp ├── proto ├── fbe.cpp ├── fbe.h ├── fbe_models.cpp ├── fbe_models.h ├── fbe_models.inl ├── fbe_protocol.cpp ├── fbe_protocol.h ├── simple.cpp ├── simple.fbe ├── simple.h ├── simple_models.cpp ├── simple_models.h ├── simple_protocol.cpp └── simple_protocol.h ├── source └── server │ ├── asio │ ├── service.cpp │ ├── ssl_client.cpp │ ├── ssl_context.cpp │ ├── ssl_server.cpp │ ├── ssl_session.cpp │ ├── tcp_client.cpp │ ├── tcp_resolver.cpp │ ├── tcp_server.cpp │ ├── tcp_session.cpp │ ├── timer.cpp │ ├── udp_client.cpp │ ├── udp_resolver.cpp │ └── udp_server.cpp │ ├── http │ ├── http_client.cpp │ ├── http_request.cpp │ ├── http_response.cpp │ ├── http_server.cpp │ ├── http_session.cpp │ ├── https_client.cpp │ ├── https_server.cpp │ └── https_session.cpp │ └── ws │ ├── ws.cpp │ ├── ws_client.cpp │ ├── ws_server.cpp │ ├── ws_session.cpp │ ├── wss_client.cpp │ ├── wss_server.cpp │ └── wss_session.cpp ├── tests ├── test.cpp ├── test.h ├── test_http.cpp ├── test_https.cpp ├── test_proto.cpp ├── test_ssl.cpp ├── test_tcp.cpp ├── test_timer.cpp ├── test_udp.cpp ├── test_udp_multicast.cpp ├── test_ws.cpp └── test_wss.cpp ├── tools └── certificates │ ├── ca-secret.key │ ├── ca.crt │ ├── ca.key │ ├── ca.pem │ ├── ca.pfx │ ├── client-secret.key │ ├── client.crt │ ├── client.csr │ ├── client.key │ ├── client.pem │ ├── client.pfx │ ├── dh4096.pem │ ├── generate.bat │ ├── generate.sh │ ├── server-secret.key │ ├── server.crt │ ├── server.csr │ ├── server.key │ ├── server.pem │ └── server.pfx └── www ├── api ├── .gitignore ├── index.html ├── openapi.yaml └── swagger.js ├── ws ├── favicon.png └── index.html └── wss ├── favicon.png └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | bin/* linguist-vendored 2 | build/* linguist-vendored 3 | cmake/* linguist-vendored 4 | documents/* linguist-vendored 5 | images/* linguist-vendored 6 | modules/* linguist-vendored 7 | temp/* linguist-vendored 8 | tools/* linguist-vendored 9 | www/* linguist-vendored 10 | -------------------------------------------------------------------------------- /.github/workflows/build-linux-clang.yml: -------------------------------------------------------------------------------- 1 | name: Linux (clang) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup required packages" 15 | run: sudo apt-get install -y binutils-dev libc++-dev libssl-dev uuid-dev 16 | 17 | - name: "Setup clang" 18 | uses: egor-tensin/setup-clang@v1 19 | 20 | - name: "Setup cmake" 21 | run: cmake --version 22 | 23 | - name: "Setup gil" 24 | run: | 25 | pip3 install gil 26 | gil update 27 | 28 | - name: "Build" 29 | run: | 30 | cd build 31 | ./unix.sh 32 | -------------------------------------------------------------------------------- /.github/workflows/build-linux-gcc.yml: -------------------------------------------------------------------------------- 1 | name: Linux (gcc) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup required packages" 15 | run: sudo apt-get install -y binutils-dev libssl-dev uuid-dev 16 | 17 | - name: "Setup gcc" 18 | uses: egor-tensin/setup-gcc@v1 19 | 20 | - name: "Setup cmake" 21 | run: cmake --version 22 | 23 | - name: "Setup gil" 24 | run: | 25 | pip3 install gil 26 | gil update 27 | 28 | - name: "Build" 29 | run: | 30 | cd build 31 | ./unix.sh 32 | -------------------------------------------------------------------------------- /.github/workflows/build-macos.yml: -------------------------------------------------------------------------------- 1 | name: MacOS 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: macos-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup python" 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.x' 18 | 19 | - name: "Setup cmake" 20 | run: cmake --version 21 | 22 | - name: "Setup gil" 23 | run: | 24 | pip3 install gil 25 | gil update 26 | 27 | - name: "Build" 28 | run: | 29 | cd build 30 | ./unix.sh 31 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-mingw.yml: -------------------------------------------------------------------------------- 1 | name: Windows (MinGW) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup cmake" 15 | run: cmake --version 16 | 17 | - name: "Setup gil" 18 | run: | 19 | pip3 install gil 20 | gil update 21 | 22 | - name: "Build" 23 | env: 24 | INCLUDE: C:\mingw64\x86_64-w64-mingw32\include 25 | LIB: C:\mingw64\x86_64-w64-mingw32\lib 26 | run: | 27 | cd build 28 | ./mingw.bat 29 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-msys2.yml: -------------------------------------------------------------------------------- 1 | name: Windows (MSYS2) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | defaults: 12 | run: 13 | shell: msys2 {0} 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: "Setup MSYS2" 18 | uses: msys2/setup-msys2@v2 19 | with: 20 | msystem: UCRT64 21 | release: false 22 | install: >- 23 | git 24 | make 25 | mingw-w64-ucrt-x86_64-cmake 26 | mingw-w64-ucrt-x86_64-gcc 27 | mingw-w64-ucrt-x86_64-doxygen 28 | mingw-w64-ucrt-x86_64-graphviz 29 | msys2-w32api-runtime 30 | python-pip 31 | 32 | - name: "Setup cmake" 33 | run: cmake --version 34 | 35 | - name: "Setup gil" 36 | run: | 37 | pip3 install gil --break-system-packages 38 | gil update 39 | 40 | - name: "Build" 41 | env: 42 | INCLUDE: C:\msys64\usr\include\w32api 43 | LIB: C:\msys64\usr\lib\w32api 44 | run: | 45 | cd build 46 | ./unix.sh 47 | -------------------------------------------------------------------------------- /.github/workflows/build-windows-vs.yml: -------------------------------------------------------------------------------- 1 | name: Windows (Visual Studio) 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: "Setup Visual Studio" 15 | uses: egor-tensin/vs-shell@v2 16 | 17 | - name: "Setup cmake" 18 | run: cmake --version 19 | 20 | - name: "Setup gil" 21 | run: | 22 | pip3 install gil 23 | gil update 24 | 25 | - name: "Build" 26 | run: | 27 | cd build 28 | ./vs.bat 29 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Setup git" 13 | run: | 14 | git config --global user.name "${{ github.actor }}" 15 | git config --global user.email "${{ github.actor }}@users.noreply.github.com" 16 | 17 | - uses: actions/checkout@v4 18 | 19 | - name: "Setup cmake" 20 | run: cmake --version 21 | 22 | - name: "Setup doxygen" 23 | run: | 24 | sudo apt-get -y install doxygen doxygen-latex graphviz binutils-dev 25 | doxygen --version 26 | dot -V 27 | 28 | - name: "Setup gil" 29 | run: | 30 | pip3 install gil 31 | gil update 32 | 33 | - name: "Doxygen" 34 | env: 35 | GITHUB_ACTOR: ${{ github.actor }} 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | run: | 38 | cd build/Unix 39 | ./01-generate.sh 40 | ./05-doxygen.sh 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | build 3 | 4 | # CMake 5 | build 6 | cmake 7 | cmake-build-* 8 | 9 | # Ctags files 10 | tags 11 | tags.idx 12 | 13 | # Modules 14 | modules/* 15 | !modules/CMakeLists.txt 16 | !modules/*.cmake 17 | 18 | # Temporary 19 | .idea 20 | temp 21 | -------------------------------------------------------------------------------- /.gitlinks: -------------------------------------------------------------------------------- 1 | # Modules 2 | asio modules/asio https://github.com/chriskohlhoff/asio.git asio-1-32-0 3 | Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git devel 4 | cpp-optparse modules/cpp-optparse https://github.com/chronoxor/cpp-optparse.git main 5 | CppBenchmark modules/CppBenchmark https://github.com/chronoxor/CppBenchmark.git master 6 | CppCommon modules/CppCommon https://github.com/chronoxor/CppCommon.git master 7 | OpenSSL modules/OpenSSL https://github.com/chronoxor/OpenSSL.git master 8 | swagger-ui modules/swagger-ui https://github.com/swagger-api/swagger-ui.git master dist www/api/swagger 9 | 10 | # Scripts 11 | build build https://github.com/chronoxor/CppBuildScripts.git master 12 | cmake cmake https://github.com/chronoxor/CppCMakeScripts.git master 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2026 Ivan Shynkarenka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # CppServer todo 2 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /examples/asio_service.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file asio_service.cpp 3 | \brief Asio service example 4 | \author Ivan Shynkarenka 5 | \date 15.01.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "threads/thread.h" 12 | 13 | #include 14 | 15 | int main(int argc, char** argv) 16 | { 17 | // Create a new Asio service 18 | auto service = std::make_shared(); 19 | 20 | // Start the Asio service 21 | std::cout << "Asio service starting..."; 22 | service->Start(); 23 | std::cout << "Done!" << std::endl; 24 | 25 | // Dispatch 26 | std::cout << "1 - Dispatch from the main thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 27 | service->Dispatch([service]() 28 | { 29 | std::cout << "1.1 - Dispatched in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 30 | 31 | std::cout << "1.2 - Dispatch from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 32 | service->Dispatch([service]() 33 | { 34 | std::cout << "1.2.1 - Dispatched in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 35 | }); 36 | 37 | std::cout << "1.3 - Post from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 38 | service->Post([service]() 39 | { 40 | std::cout << "1.3.1 - Posted in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 41 | }); 42 | }); 43 | 44 | // Post 45 | std::cout << "2 - Post from the main thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 46 | service->Post([service]() 47 | { 48 | std::cout << "2.1 - Posted in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 49 | 50 | std::cout << "2.2 - Dispatch from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 51 | service->Dispatch([service]() 52 | { 53 | std::cout << "2.2.1 - Dispatched in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 54 | }); 55 | 56 | std::cout << "2.3 - Post from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 57 | service->Post([service]() 58 | { 59 | std::cout << "2.3.1 - Posted in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl; 60 | }); 61 | }); 62 | 63 | // Wait for a while... 64 | CppCommon::Thread::Sleep(1000); 65 | 66 | // Stop the Asio service 67 | std::cout << "Asio service stopping..."; 68 | service->Stop(); 69 | std::cout << "Done!" << std::endl; 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /examples/asio_service.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file asio_service.h 3 | \brief Asio service example 4 | \author Ivan Shynkarenka 5 | \date 15.01.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/asio/service.h" 10 | 11 | class AsioService : public CppServer::Asio::Service 12 | { 13 | public: 14 | using CppServer::Asio::Service::Service; 15 | 16 | protected: 17 | void onError(int error, const std::string& category, const std::string& message) override 18 | { 19 | std::cout << "Asio service caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /examples/asio_timer.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file asio_timer.cpp 3 | \brief Asio timer example 4 | \author Ivan Shynkarenka 5 | \date 16.08.2018 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/timer.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | 16 | class AsioTimer : public CppServer::Asio::Timer 17 | { 18 | public: 19 | using CppServer::Asio::Timer::Timer; 20 | 21 | protected: 22 | void onTimer(bool canceled) override 23 | { 24 | std::cout << "Asio timer " << (canceled ? "canceled" : "expired") << std::endl; 25 | } 26 | 27 | void onError(int error, const std::string& category, const std::string& message) override 28 | { 29 | std::cout << "Asio timer caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 30 | } 31 | }; 32 | 33 | int main(int argc, char** argv) 34 | { 35 | // Create a new Asio service 36 | auto service = std::make_shared(); 37 | 38 | // Start the Asio service 39 | std::cout << "Asio service starting..."; 40 | service->Start(); 41 | std::cout << "Done!" << std::endl; 42 | 43 | // Create a new Asio timer 44 | auto timer = std::make_shared(service); 45 | 46 | // Setup and synchronously wait for the timer 47 | timer->Setup(CppCommon::UtcTime() + CppCommon::Timespan::seconds(1)); 48 | timer->WaitSync(); 49 | 50 | // Setup and asynchronously wait for the timer 51 | timer->Setup(CppCommon::Timespan::seconds(1)); 52 | timer->WaitAsync(); 53 | 54 | // Wait for a while... 55 | CppCommon::Thread::Sleep(2000); 56 | 57 | // Setup and asynchronously wait for the timer 58 | timer->Setup(CppCommon::Timespan::seconds(1)); 59 | timer->WaitAsync(); 60 | 61 | // Wait for a while... 62 | CppCommon::Thread::Sleep(500); 63 | 64 | // Cancel the timer 65 | timer->Cancel(); 66 | 67 | // Wait for a while... 68 | CppCommon::Thread::Sleep(500); 69 | 70 | // Stop the Asio service 71 | std::cout << "Asio service stopping..."; 72 | service->Stop(); 73 | std::cout << "Done!" << std::endl; 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /examples/http_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_client.cpp 3 | \brief HTTP client example 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/http/http_client.h" 12 | #include "string/string_utils.h" 13 | 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | // HTTP server address 19 | std::string address = "127.0.0.1"; 20 | if (argc > 1) 21 | address = argv[1]; 22 | // HTTP server port 23 | int port = 8080; 24 | if (argc > 2) 25 | port = std::atoi(argv[2]); 26 | 27 | std::cout << "HTTP server address: " << address << std::endl; 28 | std::cout << "HTTP server port: " << port << std::endl; 29 | 30 | std::cout << std::endl; 31 | 32 | // Create a new Asio service 33 | auto service = std::make_shared(); 34 | 35 | // Start the Asio service 36 | std::cout << "Asio service starting..."; 37 | service->Start(); 38 | std::cout << "Done!" << std::endl; 39 | 40 | // Create a new HTTP client 41 | auto client = std::make_shared(service, address, port); 42 | 43 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 44 | 45 | try 46 | { 47 | // Perform text input 48 | std::string line; 49 | while (getline(std::cin, line)) 50 | { 51 | if (line.empty()) 52 | break; 53 | 54 | // Reconnect the client 55 | if (line == "!") 56 | { 57 | std::cout << "Client reconnecting..."; 58 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 59 | std::cout << "Done!" << std::endl; 60 | continue; 61 | } 62 | 63 | auto commands = CppCommon::StringUtils::Split(line, ' ', true); 64 | if (commands.size() < 2) 65 | { 66 | std::cout << "HTTP method and URL must be entered!" << std::endl; 67 | continue; 68 | } 69 | 70 | if (CppCommon::StringUtils::ToUpper(commands[0]) == "HEAD") 71 | { 72 | auto response = client->SendHeadRequest(commands[1]).get(); 73 | std::cout << response << std::endl; 74 | } 75 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "GET") 76 | { 77 | auto response = client->SendGetRequest(commands[1]).get(); 78 | std::cout << response << std::endl; 79 | } 80 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "POST") 81 | { 82 | if (commands.size() < 3) 83 | { 84 | std::cout << "HTTP method, URL and body must be entered!" << std::endl; 85 | continue; 86 | } 87 | auto response = client->SendPostRequest(commands[1], commands[2]).get(); 88 | std::cout << response << std::endl; 89 | } 90 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "PUT") 91 | { 92 | if (commands.size() < 3) 93 | { 94 | std::cout << "HTTP method, URL and body must be entered!" << std::endl; 95 | continue; 96 | } 97 | auto response = client->SendPutRequest(commands[1], commands[2]).get(); 98 | std::cout << response << std::endl; 99 | } 100 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "DELETE") 101 | { 102 | auto response = client->SendDeleteRequest(commands[1]).get(); 103 | std::cout << response << std::endl; 104 | } 105 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "OPTIONS") 106 | { 107 | auto response = client->SendOptionsRequest(commands[1]).get(); 108 | std::cout << response << std::endl; 109 | } 110 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "TRACE") 111 | { 112 | auto response = client->SendTraceRequest(commands[1]).get(); 113 | std::cout << response << std::endl; 114 | } 115 | else 116 | std::cout << "Unknown HTTP method: " << commands[0] << std::endl; 117 | } 118 | } 119 | catch (const std::exception& ex) 120 | { 121 | std::cerr << ex.what() << std::endl; 122 | } 123 | 124 | // Stop the Asio service 125 | std::cout << "Asio service stopping..."; 126 | service->Stop(); 127 | std::cout << "Done!" << std::endl; 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /examples/https_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file https_client.cpp 3 | \brief HTTPS client example 4 | \author Ivan Shynkarenka 5 | \date 12.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/http/https_client.h" 12 | #include "string/string_utils.h" 13 | 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | // HTTP server address 19 | std::string address = "127.0.0.1"; 20 | if (argc > 1) 21 | address = argv[1]; 22 | // HTTP server port 23 | int port = 8443; 24 | if (argc > 2) 25 | port = std::atoi(argv[2]); 26 | 27 | std::cout << "HTTPS server address: " << address << std::endl; 28 | std::cout << "HTTPS server port: " << port << std::endl; 29 | 30 | std::cout << std::endl; 31 | 32 | // Create a new Asio service 33 | auto service = std::make_shared(); 34 | 35 | // Start the Asio service 36 | std::cout << "Asio service starting..."; 37 | service->Start(); 38 | std::cout << "Done!" << std::endl; 39 | 40 | // Create and prepare a new SSL client context 41 | auto context = std::make_shared(asio::ssl::context::tlsv13); 42 | context->set_default_verify_paths(); 43 | context->set_root_certs(); 44 | context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert); 45 | context->load_verify_file("../tools/certificates/ca.pem"); 46 | 47 | // Create a new HTTP client 48 | auto client = std::make_shared(service, context, address, port); 49 | 50 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 51 | 52 | try 53 | { 54 | // Perform text input 55 | std::string line; 56 | while (getline(std::cin, line)) 57 | { 58 | if (line.empty()) 59 | break; 60 | 61 | // Reconnect the client 62 | if (line == "!") 63 | { 64 | std::cout << "Client reconnecting..."; 65 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 66 | std::cout << "Done!" << std::endl; 67 | continue; 68 | } 69 | 70 | auto commands = CppCommon::StringUtils::Split(line, ' ', true); 71 | if (commands.size() < 2) 72 | { 73 | std::cout << "HTTP method and URL must be entered!" << std::endl; 74 | continue; 75 | } 76 | 77 | if (CppCommon::StringUtils::ToUpper(commands[0]) == "HEAD") 78 | { 79 | auto response = client->SendHeadRequest(commands[1]).get(); 80 | std::cout << response << std::endl; 81 | } 82 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "GET") 83 | { 84 | auto response = client->SendGetRequest(commands[1]).get(); 85 | std::cout << response << std::endl; 86 | } 87 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "POST") 88 | { 89 | if (commands.size() < 3) 90 | { 91 | std::cout << "HTTP method, URL and body must be entered!" << std::endl; 92 | continue; 93 | } 94 | auto response = client->SendPostRequest(commands[1], commands[2]).get(); 95 | std::cout << response << std::endl; 96 | } 97 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "PUT") 98 | { 99 | if (commands.size() < 3) 100 | { 101 | std::cout << "HTTP method, URL and body must be entered!" << std::endl; 102 | continue; 103 | } 104 | auto response = client->SendPutRequest(commands[1], commands[2]).get(); 105 | std::cout << response << std::endl; 106 | } 107 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "DELETE") 108 | { 109 | auto response = client->SendDeleteRequest(commands[1]).get(); 110 | std::cout << response << std::endl; 111 | } 112 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "OPTIONS") 113 | { 114 | auto response = client->SendOptionsRequest(commands[1]).get(); 115 | std::cout << response << std::endl; 116 | } 117 | else if (CppCommon::StringUtils::ToUpper(commands[0]) == "TRACE") 118 | { 119 | auto response = client->SendTraceRequest(commands[1]).get(); 120 | std::cout << response << std::endl; 121 | } 122 | else 123 | std::cout << "Unknown HTTP method: " << commands[0] << std::endl; 124 | } 125 | } 126 | catch (const std::exception& ex) 127 | { 128 | std::cerr << ex.what() << std::endl; 129 | } 130 | 131 | // Stop the Asio service 132 | std::cout << "Asio service stopping..."; 133 | service->Stop(); 134 | std::cout << "Done!" << std::endl; 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /examples/proto_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file proto_client.cpp 3 | \brief Simple protocol client example 4 | \author Ivan Shynkarenka 5 | \date 05.01.2022 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/tcp_client.h" 12 | #include "string/format.h" 13 | #include "threads/thread.h" 14 | 15 | #include "../proto/simple_protocol.h" 16 | 17 | #include 18 | #include 19 | 20 | class SimpleProtoClient : public CppServer::Asio::TCPClient, public FBE::simple::Client 21 | { 22 | public: 23 | using CppServer::Asio::TCPClient::TCPClient; 24 | 25 | void DisconnectAndStop() 26 | { 27 | _stop = true; 28 | DisconnectAsync(); 29 | while (IsConnected()) 30 | CppCommon::Thread::Yield(); 31 | } 32 | 33 | protected: 34 | void onConnected() override 35 | { 36 | std::cout << "Simple protocol client connected a new session with Id " << id() << std::endl; 37 | 38 | // Reset FBE protocol buffers 39 | reset(); 40 | } 41 | 42 | void onDisconnected() override 43 | { 44 | std::cout << "Simple protocol client disconnected a session with Id " << id() << std::endl; 45 | 46 | // Wait for a while... 47 | CppCommon::Thread::Sleep(1000); 48 | 49 | // Try to connect again 50 | if (!_stop) 51 | ConnectAsync(); 52 | } 53 | 54 | void onError(int error, const std::string& category, const std::string& message) override 55 | { 56 | std::cout << "Simple protocol client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 57 | } 58 | 59 | // Protocol handlers 60 | void onReceive(const ::simple::DisconnectRequest& request) override { Client::onReceive(request); std::cout << "Received: " << request << std::endl; DisconnectAsync(); } 61 | void onReceive(const ::simple::SimpleResponse& response) override { Client::onReceive(response); std::cout << "Received: " << response << std::endl; } 62 | void onReceive(const ::simple::SimpleReject& reject) override { Client::onReceive(reject); std::cout << "Received: " << reject << std::endl; } 63 | void onReceive(const ::simple::SimpleNotify& notify) override { Client::onReceive(notify); std::cout << "Received: " << notify << std::endl; } 64 | 65 | // Protocol implementation 66 | void onReceived(const void* buffer, size_t size) override { receive(buffer, size); } 67 | size_t onSend(const void* data, size_t size) override { return SendAsync(data, size) ? size : 0; } 68 | 69 | private: 70 | std::atomic _stop{false}; 71 | }; 72 | 73 | int main(int argc, char** argv) 74 | { 75 | // Simple protocol server address 76 | std::string address = "127.0.0.1"; 77 | if (argc > 1) 78 | address = argv[1]; 79 | 80 | // Simple protocol server port 81 | int port = 4444; 82 | if (argc > 2) 83 | port = std::atoi(argv[2]); 84 | 85 | std::cout << "Simple protocol server address: " << address << std::endl; 86 | std::cout << "Simple protocol server port: " << port << std::endl; 87 | 88 | std::cout << std::endl; 89 | 90 | // Create a new Asio service 91 | auto service = std::make_shared(); 92 | 93 | // Start the Asio service 94 | std::cout << "Asio service starting..."; 95 | service->Start(); 96 | std::cout << "Done!" << std::endl; 97 | 98 | // Create a new simple protocol client 99 | auto client = std::make_shared(service, address, port); 100 | 101 | // Connect the client 102 | std::cout << "Client connecting..."; 103 | client->ConnectAsync(); 104 | std::cout << "Done!" << std::endl; 105 | 106 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 107 | 108 | // Perform text input 109 | std::string line; 110 | while (getline(std::cin, line)) 111 | { 112 | if (line.empty()) 113 | break; 114 | 115 | // Reconnect the client 116 | if (line == "!") 117 | { 118 | std::cout << "Client reconnecting..."; 119 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 120 | std::cout << "Done!" << std::endl; 121 | continue; 122 | } 123 | 124 | // Send request to the simple protocol server 125 | simple::SimpleRequest request; 126 | request.Message = line; 127 | auto response = client->request(request).get(); 128 | 129 | // Show string hash calculation result 130 | std::cout << "Hash of '" << line << "' = " << CppCommon::format("0x{:08X}", response.Hash) << std::endl; 131 | } 132 | 133 | // Disconnect the client 134 | std::cout << "Client disconnecting..."; 135 | client->DisconnectAndStop(); 136 | std::cout << "Done!" << std::endl; 137 | 138 | // Stop the Asio service 139 | std::cout << "Asio service stopping..."; 140 | service->Stop(); 141 | std::cout << "Done!" << std::endl; 142 | 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /examples/ssl_chat_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ssl_chat_client.cpp 3 | \brief SSL chat client example 4 | \author Ivan Shynkarenka 5 | \date 01.01.2017 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/ssl_client.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | #include 16 | 17 | class ChatClient : public CppServer::Asio::SSLClient 18 | { 19 | public: 20 | using CppServer::Asio::SSLClient::SSLClient; 21 | 22 | void DisconnectAndStop() 23 | { 24 | _stop = true; 25 | DisconnectAsync(); 26 | while (IsConnected()) 27 | CppCommon::Thread::Yield(); 28 | } 29 | 30 | protected: 31 | void onConnected() override 32 | { 33 | std::cout << "Chat SSL client connected a new session with Id " << id() << std::endl; 34 | } 35 | 36 | void onHandshaked() override 37 | { 38 | std::cout << "Chat SSL client handshaked a new session with Id " << id() << std::endl; 39 | } 40 | 41 | void onDisconnected() override 42 | { 43 | std::cout << "Chat SSL client disconnected a session with Id " << id() << std::endl; 44 | 45 | // Wait for a while... 46 | CppCommon::Thread::Sleep(1000); 47 | 48 | // Try to connect again 49 | if (!_stop) 50 | ConnectAsync(); 51 | } 52 | 53 | void onReceived(const void* buffer, size_t size) override 54 | { 55 | std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl; 56 | } 57 | 58 | void onError(int error, const std::string& category, const std::string& message) override 59 | { 60 | std::cout << "Chat SSL client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 61 | } 62 | 63 | private: 64 | std::atomic _stop{false}; 65 | }; 66 | 67 | int main(int argc, char** argv) 68 | { 69 | // SSL server address 70 | std::string address = "127.0.0.1"; 71 | if (argc > 1) 72 | address = argv[1]; 73 | 74 | // SSL server port 75 | int port = 2222; 76 | if (argc > 2) 77 | port = std::atoi(argv[2]); 78 | 79 | std::cout << "SSL server address: " << address << std::endl; 80 | std::cout << "SSL server port: " << port << std::endl; 81 | 82 | std::cout << std::endl; 83 | 84 | // Create a new Asio service 85 | auto service = std::make_shared(); 86 | 87 | // Start the Asio service 88 | std::cout << "Asio service starting..."; 89 | service->Start(); 90 | std::cout << "Done!" << std::endl; 91 | 92 | // Create and prepare a new SSL client context 93 | auto context = std::make_shared(asio::ssl::context::tlsv13); 94 | context->set_default_verify_paths(); 95 | context->set_root_certs(); 96 | context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert); 97 | context->load_verify_file("../tools/certificates/ca.pem"); 98 | 99 | // Create a new SSL chat client 100 | auto client = std::make_shared(service, context, address, port); 101 | 102 | // Connect the client 103 | std::cout << "Client connecting..."; 104 | client->ConnectAsync(); 105 | std::cout << "Done!" << std::endl; 106 | 107 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 108 | 109 | // Perform text input 110 | std::string line; 111 | while (getline(std::cin, line)) 112 | { 113 | if (line.empty()) 114 | break; 115 | 116 | // Reconnect the client 117 | if (line == "!") 118 | { 119 | std::cout << "Client reconnecting..."; 120 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 121 | std::cout << "Done!" << std::endl; 122 | continue; 123 | } 124 | 125 | // Send the entered text to the chat server 126 | client->SendAsync(line); 127 | } 128 | 129 | // Disconnect the client 130 | std::cout << "Client disconnecting..."; 131 | client->DisconnectAndStop(); 132 | std::cout << "Done!" << std::endl; 133 | 134 | // Stop the Asio service 135 | std::cout << "Asio service stopping..."; 136 | service->Stop(); 137 | std::cout << "Done!" << std::endl; 138 | 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /examples/ssl_chat_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ssl_chat_server.cpp 3 | \brief SSL chat server example 4 | \author Ivan Shynkarenka 5 | \date 30.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/ssl_server.h" 12 | 13 | #include 14 | 15 | class ChatSession : public CppServer::Asio::SSLSession 16 | { 17 | public: 18 | using CppServer::Asio::SSLSession::SSLSession; 19 | 20 | protected: 21 | void onConnected() override 22 | { 23 | std::cout << "Chat SSL session with Id " << id() << " connected!" << std::endl; 24 | } 25 | 26 | void onHandshaked() override 27 | { 28 | std::cout << "Chat SSL session with Id " << id() << " handshaked!" << std::endl; 29 | 30 | // Send invite message 31 | std::string message("Hello from SSL chat! Please send a message or '!' to disconnect the client!"); 32 | SendAsync(message.data(), message.size()); 33 | } 34 | 35 | void onDisconnected() override 36 | { 37 | std::cout << "Chat SSL session with Id " << id() << " disconnected!" << std::endl; 38 | } 39 | 40 | void onReceived(const void* buffer, size_t size) override 41 | { 42 | std::string message((const char*)buffer, size); 43 | std::cout << "Incoming: " << message << std::endl; 44 | 45 | // Multicast message to all connected sessions 46 | server()->Multicast(message); 47 | 48 | // If the buffer starts with '!' the disconnect the current session 49 | if (message == "!") 50 | Disconnect(); 51 | } 52 | 53 | void onError(int error, const std::string& category, const std::string& message) override 54 | { 55 | std::cout << "Chat SSL session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 56 | } 57 | }; 58 | 59 | class ChatServer : public CppServer::Asio::SSLServer 60 | { 61 | public: 62 | using CppServer::Asio::SSLServer::SSLServer; 63 | 64 | protected: 65 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 66 | { 67 | return std::make_shared(server); 68 | } 69 | 70 | protected: 71 | void onError(int error, const std::string& category, const std::string& message) override 72 | { 73 | std::cout << "Chat TCP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 74 | } 75 | }; 76 | 77 | int main(int argc, char** argv) 78 | { 79 | // SSL server port 80 | int port = 2222; 81 | if (argc > 1) 82 | port = std::atoi(argv[1]); 83 | 84 | std::cout << "SSL server port: " << port << std::endl; 85 | 86 | std::cout << std::endl; 87 | 88 | // Create a new Asio service 89 | auto service = std::make_shared(); 90 | 91 | // Start the Asio service 92 | std::cout << "Asio service starting..."; 93 | service->Start(); 94 | std::cout << "Done!" << std::endl; 95 | 96 | // Create and prepare a new SSL server context 97 | auto context = std::make_shared(asio::ssl::context::tlsv13); 98 | context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; }); 99 | context->use_certificate_chain_file("../tools/certificates/server.pem"); 100 | context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem); 101 | context->use_tmp_dh_file("../tools/certificates/dh4096.pem"); 102 | 103 | // Create a new SSL chat server 104 | auto server = std::make_shared(service, context, port); 105 | 106 | // Start the server 107 | std::cout << "Server starting..."; 108 | server->Start(); 109 | std::cout << "Done!" << std::endl; 110 | 111 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 112 | 113 | // Perform text input 114 | std::string line; 115 | while (getline(std::cin, line)) 116 | { 117 | if (line.empty()) 118 | break; 119 | 120 | // Restart the server 121 | if (line == "!") 122 | { 123 | std::cout << "Server restarting..."; 124 | server->Restart(); 125 | std::cout << "Done!" << std::endl; 126 | continue; 127 | } 128 | 129 | // Multicast admin message to all sessions 130 | line = "(admin) " + line; 131 | server->Multicast(line); 132 | } 133 | 134 | // Stop the server 135 | std::cout << "Server stopping..."; 136 | server->Stop(); 137 | std::cout << "Done!" << std::endl; 138 | 139 | // Stop the Asio service 140 | std::cout << "Asio service stopping..."; 141 | service->Stop(); 142 | std::cout << "Done!" << std::endl; 143 | 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /examples/tcp_chat_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file tcp_chat_client.cpp 3 | \brief TCP chat client example 4 | \author Ivan Shynkarenka 5 | \date 14.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/tcp_client.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | #include 16 | 17 | class ChatClient : public CppServer::Asio::TCPClient 18 | { 19 | public: 20 | using CppServer::Asio::TCPClient::TCPClient; 21 | 22 | void DisconnectAndStop() 23 | { 24 | _stop = true; 25 | DisconnectAsync(); 26 | while (IsConnected()) 27 | CppCommon::Thread::Yield(); 28 | } 29 | 30 | protected: 31 | void onConnected() override 32 | { 33 | std::cout << "Chat TCP client connected a new session with Id " << id() << std::endl; 34 | } 35 | 36 | void onDisconnected() override 37 | { 38 | std::cout << "Chat TCP client disconnected a session with Id " << id() << std::endl; 39 | 40 | // Wait for a while... 41 | CppCommon::Thread::Sleep(1000); 42 | 43 | // Try to connect again 44 | if (!_stop) 45 | ConnectAsync(); 46 | } 47 | 48 | void onReceived(const void* buffer, size_t size) override 49 | { 50 | std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl; 51 | } 52 | 53 | void onError(int error, const std::string& category, const std::string& message) override 54 | { 55 | std::cout << "Chat TCP client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 56 | } 57 | 58 | private: 59 | std::atomic _stop{false}; 60 | }; 61 | 62 | int main(int argc, char** argv) 63 | { 64 | // TCP server address 65 | std::string address = "127.0.0.1"; 66 | if (argc > 1) 67 | address = argv[1]; 68 | 69 | // TCP server port 70 | int port = 1111; 71 | if (argc > 2) 72 | port = std::atoi(argv[2]); 73 | 74 | std::cout << "TCP server address: " << address << std::endl; 75 | std::cout << "TCP server port: " << port << std::endl; 76 | 77 | std::cout << std::endl; 78 | 79 | // Create a new Asio service 80 | auto service = std::make_shared(); 81 | 82 | // Start the Asio service 83 | std::cout << "Asio service starting..."; 84 | service->Start(); 85 | std::cout << "Done!" << std::endl; 86 | 87 | // Create a new TCP chat client 88 | auto client = std::make_shared(service, address, port); 89 | 90 | // Connect the client 91 | std::cout << "Client connecting..."; 92 | client->ConnectAsync(); 93 | std::cout << "Done!" << std::endl; 94 | 95 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 96 | 97 | // Perform text input 98 | std::string line; 99 | while (getline(std::cin, line)) 100 | { 101 | if (line.empty()) 102 | break; 103 | 104 | // Reconnect the client 105 | if (line == "!") 106 | { 107 | std::cout << "Client reconnecting..."; 108 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 109 | std::cout << "Done!" << std::endl; 110 | continue; 111 | } 112 | 113 | // Send the entered text to the chat server 114 | client->SendAsync(line); 115 | } 116 | 117 | // Disconnect the client 118 | std::cout << "Client disconnecting..."; 119 | client->DisconnectAndStop(); 120 | std::cout << "Done!" << std::endl; 121 | 122 | // Stop the Asio service 123 | std::cout << "Asio service stopping..."; 124 | service->Stop(); 125 | std::cout << "Done!" << std::endl; 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /examples/tcp_chat_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file tcp_chat_server.cpp 3 | \brief TCP chat server example 4 | \author Ivan Shynkarenka 5 | \date 14.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/tcp_server.h" 12 | 13 | #include 14 | 15 | class ChatSession : public CppServer::Asio::TCPSession 16 | { 17 | public: 18 | using CppServer::Asio::TCPSession::TCPSession; 19 | 20 | protected: 21 | void onConnected() override 22 | { 23 | std::cout << "Chat TCP session with Id " << id() << " connected!" << std::endl; 24 | 25 | // Send invite message 26 | std::string message("Hello from TCP chat! Please send a message or '!' to disconnect the client!"); 27 | SendAsync(message); 28 | } 29 | 30 | void onDisconnected() override 31 | { 32 | std::cout << "Chat TCP session with Id " << id() << " disconnected!" << std::endl; 33 | } 34 | 35 | void onReceived(const void* buffer, size_t size) override 36 | { 37 | std::string message((const char*)buffer, size); 38 | std::cout << "Incoming: " << message << std::endl; 39 | 40 | // Multicast message to all connected sessions 41 | server()->Multicast(message); 42 | 43 | // If the buffer starts with '!' the disconnect the current session 44 | if (message == "!") 45 | Disconnect(); 46 | } 47 | 48 | void onError(int error, const std::string& category, const std::string& message) override 49 | { 50 | std::cout << "Chat TCP session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 51 | } 52 | }; 53 | 54 | class ChatServer : public CppServer::Asio::TCPServer 55 | { 56 | public: 57 | using CppServer::Asio::TCPServer::TCPServer; 58 | 59 | protected: 60 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 61 | { 62 | return std::make_shared(server); 63 | } 64 | 65 | protected: 66 | void onError(int error, const std::string& category, const std::string& message) override 67 | { 68 | std::cout << "Chat TCP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 69 | } 70 | }; 71 | 72 | int main(int argc, char** argv) 73 | { 74 | // TCP server port 75 | int port = 1111; 76 | if (argc > 1) 77 | port = std::atoi(argv[1]); 78 | 79 | std::cout << "TCP server port: " << port << std::endl; 80 | 81 | std::cout << std::endl; 82 | 83 | // Create a new Asio service 84 | auto service = std::make_shared(); 85 | 86 | // Start the Asio service 87 | std::cout << "Asio service starting..."; 88 | service->Start(); 89 | std::cout << "Done!" << std::endl; 90 | 91 | // Create a new TCP chat server 92 | auto server = std::make_shared(service, port); 93 | 94 | // Start the server 95 | std::cout << "Server starting..."; 96 | server->Start(); 97 | std::cout << "Done!" << std::endl; 98 | 99 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 100 | 101 | // Perform text input 102 | std::string line; 103 | while (getline(std::cin, line)) 104 | { 105 | if (line.empty()) 106 | break; 107 | 108 | // Restart the server 109 | if (line == "!") 110 | { 111 | std::cout << "Server restarting..."; 112 | server->Restart(); 113 | std::cout << "Done!" << std::endl; 114 | continue; 115 | } 116 | 117 | // Multicast admin message to all sessions 118 | line = "(admin) " + line; 119 | server->Multicast(line); 120 | } 121 | 122 | // Stop the server 123 | std::cout << "Server stopping..."; 124 | server->Stop(); 125 | std::cout << "Done!" << std::endl; 126 | 127 | // Stop the Asio service 128 | std::cout << "Asio service stopping..."; 129 | service->Stop(); 130 | std::cout << "Done!" << std::endl; 131 | 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /examples/udp_echo_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file udp_echo_client.cpp 3 | \brief UDP echo client example 4 | \author Ivan Shynkarenka 5 | \date 23.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/udp_client.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | #include 16 | 17 | class EchoClient : public CppServer::Asio::UDPClient 18 | { 19 | public: 20 | using CppServer::Asio::UDPClient::UDPClient; 21 | 22 | void DisconnectAndStop() 23 | { 24 | _stop = true; 25 | DisconnectAsync(); 26 | while (IsConnected()) 27 | CppCommon::Thread::Yield(); 28 | } 29 | 30 | protected: 31 | void onConnected() override 32 | { 33 | std::cout << "Echo UDP client connected a new session with Id " << id() << std::endl; 34 | 35 | // Start receive datagrams 36 | ReceiveAsync(); 37 | } 38 | 39 | void onDisconnected() override 40 | { 41 | std::cout << "Echo UDP client disconnected a session with Id " << id() << std::endl; 42 | 43 | // Wait for a while... 44 | CppCommon::Thread::Sleep(1000); 45 | 46 | // Try to connect again 47 | if (!_stop) 48 | ConnectAsync(); 49 | } 50 | 51 | void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override 52 | { 53 | std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl; 54 | 55 | // Continue receive datagrams 56 | ReceiveAsync(); 57 | } 58 | 59 | void onError(int error, const std::string& category, const std::string& message) override 60 | { 61 | std::cout << "Echo UDP client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 62 | } 63 | 64 | private: 65 | std::atomic _stop{false}; 66 | }; 67 | 68 | int main(int argc, char** argv) 69 | { 70 | // UDP server address 71 | std::string address = "127.0.0.1"; 72 | if (argc > 1) 73 | address = argv[1]; 74 | 75 | // UDP server port 76 | int port = 3333; 77 | if (argc > 2) 78 | port = std::atoi(argv[2]); 79 | 80 | std::cout << "UDP server address: " << address << std::endl; 81 | std::cout << "UDP server port: " << port << std::endl; 82 | 83 | std::cout << std::endl; 84 | 85 | // Create a new Asio service 86 | auto service = std::make_shared(); 87 | 88 | // Start the Asio service 89 | std::cout << "Asio service starting..."; 90 | service->Start(); 91 | std::cout << "Done!" << std::endl; 92 | 93 | // Create a new UDP echo client 94 | auto client = std::make_shared(service, address, port); 95 | 96 | // Connect the client 97 | std::cout << "Client connecting..."; 98 | client->ConnectAsync(); 99 | std::cout << "Done!" << std::endl; 100 | 101 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 102 | 103 | // Perform text input 104 | std::string line; 105 | while (getline(std::cin, line)) 106 | { 107 | if (line.empty()) 108 | break; 109 | 110 | // Reconnect the client 111 | if (line == "!") 112 | { 113 | std::cout << "Client reconnecting..."; 114 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 115 | std::cout << "Done!" << std::endl; 116 | continue; 117 | } 118 | 119 | // Send the entered text to the echo server 120 | client->Send(line); 121 | } 122 | 123 | // Disconnect the client 124 | std::cout << "Client disconnecting..."; 125 | client->DisconnectAndStop(); 126 | std::cout << "Done!" << std::endl; 127 | 128 | // Stop the Asio service 129 | std::cout << "Asio service stopping..."; 130 | service->Stop(); 131 | std::cout << "Done!" << std::endl; 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /examples/udp_echo_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file udp_echo_server.cpp 3 | \brief UDP echo server example 4 | \author Ivan Shynkarenka 5 | \date 22.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/udp_server.h" 12 | 13 | #include 14 | 15 | class EchoServer : public CppServer::Asio::UDPServer 16 | { 17 | public: 18 | using CppServer::Asio::UDPServer::UDPServer; 19 | 20 | protected: 21 | void onStarted() override 22 | { 23 | // Start receive datagrams 24 | ReceiveAsync(); 25 | } 26 | 27 | void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override 28 | { 29 | std::string message((const char*)buffer, size); 30 | std::cout << "Incoming: " << message << std::endl; 31 | 32 | // Echo the message back to the sender 33 | SendAsync(endpoint, message); 34 | } 35 | 36 | void onSent(const asio::ip::udp::endpoint& endpoint, size_t sent) override 37 | { 38 | // Continue receive datagrams 39 | ReceiveAsync(); 40 | } 41 | 42 | void onError(int error, const std::string& category, const std::string& message) override 43 | { 44 | std::cout << "Echo UDP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 45 | } 46 | }; 47 | 48 | int main(int argc, char** argv) 49 | { 50 | // UDP server port 51 | int port = 3333; 52 | if (argc > 1) 53 | port = std::atoi(argv[1]); 54 | 55 | std::cout << "UDP server port: " << port << std::endl; 56 | 57 | std::cout << std::endl; 58 | 59 | // Create a new Asio service 60 | auto service = std::make_shared(); 61 | 62 | // Start the Asio service 63 | std::cout << "Asio service starting..."; 64 | service->Start(); 65 | std::cout << "Done!" << std::endl; 66 | 67 | // Create a new UDP echo server 68 | auto server = std::make_shared(service, port); 69 | 70 | // Start the server 71 | std::cout << "Server starting..."; 72 | server->Start(); 73 | std::cout << "Done!" << std::endl; 74 | 75 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 76 | 77 | // Perform text input 78 | std::string line; 79 | while (getline(std::cin, line)) 80 | { 81 | if (line.empty()) 82 | break; 83 | 84 | // Restart the server 85 | if (line == "!") 86 | { 87 | std::cout << "Server restarting..."; 88 | server->Restart(); 89 | std::cout << "Done!" << std::endl; 90 | continue; 91 | } 92 | } 93 | 94 | // Stop the server 95 | std::cout << "Server stopping..."; 96 | server->Stop(); 97 | std::cout << "Done!" << std::endl; 98 | 99 | // Stop the Asio service 100 | std::cout << "Asio service stopping..."; 101 | service->Stop(); 102 | std::cout << "Done!" << std::endl; 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /examples/udp_multicast_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file udp_multicast_client.cpp 3 | \brief UDP multicast client example 4 | \author Ivan Shynkarenka 5 | \date 27.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/udp_client.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | #include 16 | 17 | class MulticastClient : public CppServer::Asio::UDPClient 18 | { 19 | public: 20 | MulticastClient(const std::shared_ptr& service, const std::string& address, const std::string& multicast, int port) 21 | : CppServer::Asio::UDPClient(service, address, port), 22 | _multicast(multicast) 23 | { 24 | } 25 | 26 | void DisconnectAndStop() 27 | { 28 | _stop = true; 29 | DisconnectAsync(); 30 | while (IsConnected()) 31 | CppCommon::Thread::Yield(); 32 | } 33 | 34 | protected: 35 | void onConnected() override 36 | { 37 | std::cout << "Multicast UDP client connected a new session with Id " << id() << std::endl; 38 | 39 | // Join UDP multicast group 40 | JoinMulticastGroup(_multicast); 41 | 42 | // Start receive datagrams 43 | ReceiveAsync(); 44 | } 45 | 46 | void onDisconnected() override 47 | { 48 | std::cout << "Multicast UDP client disconnected a session with Id " << id() << std::endl; 49 | 50 | // Wait for a while... 51 | CppCommon::Thread::Sleep(1000); 52 | 53 | // Try to connect again 54 | if (!_stop) 55 | ConnectAsync(); 56 | } 57 | 58 | void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override 59 | { 60 | std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl; 61 | 62 | // Continue receive datagrams 63 | ReceiveAsync(); 64 | } 65 | 66 | void onError(int error, const std::string& category, const std::string& message) override 67 | { 68 | std::cout << "Multicast UDP client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 69 | } 70 | 71 | private: 72 | std::atomic _stop{false}; 73 | std::string _multicast; 74 | }; 75 | 76 | int main(int argc, char** argv) 77 | { 78 | // UDP listen address 79 | std::string listen_address = "0.0.0.0"; 80 | if (argc > 1) 81 | listen_address = argv[1]; 82 | 83 | // UDP multicast address 84 | std::string multicast_address = "239.255.0.1"; 85 | if (argc > 2) 86 | multicast_address = argv[2]; 87 | 88 | // UDP multicast port 89 | int multicast_port = 3334; 90 | if (argc > 3) 91 | multicast_port = std::atoi(argv[3]); 92 | 93 | std::cout << "UDP listen address: " << listen_address << std::endl; 94 | std::cout << "UDP multicast address: " << multicast_address << std::endl; 95 | std::cout << "UDP multicast port: " << multicast_port << std::endl; 96 | 97 | std::cout << std::endl; 98 | 99 | // Create a new Asio service 100 | auto service = std::make_shared(); 101 | 102 | // Start the Asio service 103 | std::cout << "Asio service starting..."; 104 | service->Start(); 105 | std::cout << "Done!" << std::endl; 106 | 107 | // Create a new UDP multicast client 108 | auto client = std::make_shared(service, listen_address, multicast_address, multicast_port); 109 | client->SetupMulticast(true); 110 | 111 | // Connect the client 112 | std::cout << "Client connecting..."; 113 | client->ConnectAsync(); 114 | std::cout << "Done!" << std::endl; 115 | 116 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 117 | 118 | // Perform text input 119 | std::string line; 120 | while (getline(std::cin, line)) 121 | { 122 | if (line.empty()) 123 | break; 124 | 125 | // Reconnect the client 126 | if (line == "!") 127 | { 128 | std::cout << "Client reconnecting..."; 129 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 130 | std::cout << "Done!" << std::endl; 131 | continue; 132 | } 133 | } 134 | 135 | // Disconnect the client 136 | std::cout << "Client disconnecting..."; 137 | client->DisconnectAndStop(); 138 | std::cout << "Done!" << std::endl; 139 | 140 | // Stop the Asio service 141 | std::cout << "Asio service stopping..."; 142 | service->Stop(); 143 | std::cout << "Done!" << std::endl; 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /examples/udp_multicast_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file udp_multicast_server.cpp 3 | \brief UDP multicast server example 4 | \author Ivan Shynkarenka 5 | \date 27.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/asio/udp_server.h" 12 | 13 | #include 14 | 15 | class MulticastServer : public CppServer::Asio::UDPServer 16 | { 17 | public: 18 | using CppServer::Asio::UDPServer::UDPServer; 19 | 20 | protected: 21 | void onError(int error, const std::string& category, const std::string& message) override 22 | { 23 | std::cout << "Multicast UDP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 24 | } 25 | }; 26 | 27 | int main(int argc, char** argv) 28 | { 29 | // UDP multicast address 30 | std::string multicast_address = "239.255.0.1"; 31 | if (argc > 1) 32 | multicast_address = argv[1]; 33 | 34 | // UDP multicast port 35 | int multicast_port = 3334; 36 | if (argc > 2) 37 | multicast_port = std::atoi(argv[2]); 38 | 39 | std::cout << "UDP multicast address: " << multicast_address << std::endl; 40 | std::cout << "UDP multicast port: " << multicast_port << std::endl; 41 | 42 | std::cout << std::endl; 43 | 44 | // Create a new Asio service 45 | auto service = std::make_shared(); 46 | 47 | // Start the Asio service 48 | std::cout << "Asio service starting..."; 49 | service->Start(); 50 | std::cout << "Done!" << std::endl; 51 | 52 | // Create a new UDP multicast server 53 | auto server = std::make_shared(service, 0); 54 | 55 | // Start the multicast server 56 | std::cout << "Server starting..."; 57 | server->Start(multicast_address, multicast_port); 58 | std::cout << "Done!" << std::endl; 59 | 60 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 61 | 62 | // Perform text input 63 | std::string line; 64 | while (getline(std::cin, line)) 65 | { 66 | if (line.empty()) 67 | break; 68 | 69 | // Restart the server 70 | if (line == "!") 71 | { 72 | std::cout << "Server restarting..."; 73 | server->Restart(); 74 | std::cout << "Done!" << std::endl; 75 | continue; 76 | } 77 | 78 | // Multicast admin message to all sessions 79 | line = "(admin) " + line; 80 | server->Multicast(line); 81 | } 82 | 83 | // Stop the server 84 | std::cout << "Server stopping..."; 85 | server->Stop(); 86 | std::cout << "Done!" << std::endl; 87 | 88 | // Stop the Asio service 89 | std::cout << "Asio service stopping..."; 90 | service->Stop(); 91 | std::cout << "Done!" << std::endl; 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /examples/ws_chat_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ws_chat_client.cpp 3 | \brief WebSocket chat client example 4 | \author Ivan Shynkarenka 5 | \date 22.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/ws/ws_client.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | #include 16 | 17 | class ChatClient : public CppServer::WS::WSClient 18 | { 19 | public: 20 | using CppServer::WS::WSClient::WSClient; 21 | 22 | void DisconnectAndStop() 23 | { 24 | _stop = true; 25 | CloseAsync(1000); 26 | while (IsConnected()) 27 | CppCommon::Thread::Yield(); 28 | } 29 | 30 | protected: 31 | void onWSConnecting(CppServer::HTTP::HTTPRequest& request) override 32 | { 33 | request.SetBegin("GET", "/"); 34 | request.SetHeader("Host", "localhost"); 35 | request.SetHeader("Origin", "http://localhost"); 36 | request.SetHeader("Upgrade", "websocket"); 37 | request.SetHeader("Connection", "Upgrade"); 38 | request.SetHeader("Sec-WebSocket-Key", CppCommon::Encoding::Base64Encode(ws_nonce())); 39 | request.SetHeader("Sec-WebSocket-Protocol", "chat, superchat"); 40 | request.SetHeader("Sec-WebSocket-Version", "13"); 41 | } 42 | 43 | void onWSConnected(const CppServer::HTTP::HTTPResponse& response) override 44 | { 45 | std::cout << "Chat WebSocket client connected a new session with Id " << id() << std::endl; 46 | } 47 | 48 | void onWSDisconnected() override 49 | { 50 | std::cout << "Chat WebSocket client disconnected a session with Id " << id() << std::endl; 51 | } 52 | 53 | void onWSReceived(const void* buffer, size_t size) override 54 | { 55 | std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl; 56 | } 57 | 58 | void onDisconnected() override 59 | { 60 | WSClient::onDisconnected(); 61 | 62 | // Wait for a while... 63 | CppCommon::Thread::Sleep(1000); 64 | 65 | // Try to connect again 66 | if (!_stop) 67 | ConnectAsync(); 68 | } 69 | 70 | void onError(int error, const std::string& category, const std::string& message) override 71 | { 72 | std::cout << "Chat WebSocket client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 73 | } 74 | 75 | private: 76 | std::atomic _stop{false}; 77 | }; 78 | 79 | int main(int argc, char** argv) 80 | { 81 | // WebSocket server address 82 | std::string address = "127.0.0.1"; 83 | if (argc > 1) 84 | address = argv[1]; 85 | 86 | // WebSocket server port 87 | int port = 8080; 88 | if (argc > 2) 89 | port = std::atoi(argv[2]); 90 | 91 | std::cout << "WebSocket server address: " << address << std::endl; 92 | std::cout << "WebSocket server port: " << port << std::endl; 93 | 94 | std::cout << std::endl; 95 | 96 | // Create a new Asio service 97 | auto service = std::make_shared(); 98 | 99 | // Start the Asio service 100 | std::cout << "Asio service starting..."; 101 | service->Start(); 102 | std::cout << "Done!" << std::endl; 103 | 104 | // Create a new WebSocket chat client 105 | auto client = std::make_shared(service, address, port); 106 | 107 | // Connect the client 108 | std::cout << "Client connecting..."; 109 | client->ConnectAsync(); 110 | std::cout << "Done!" << std::endl; 111 | 112 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 113 | 114 | // Perform text input 115 | std::string line; 116 | while (getline(std::cin, line)) 117 | { 118 | if (line.empty()) 119 | break; 120 | 121 | // Reconnect the client 122 | if (line == "!") 123 | { 124 | std::cout << "Client reconnecting..."; 125 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 126 | std::cout << "Done!" << std::endl; 127 | continue; 128 | } 129 | 130 | // Send the entered text to the chat server 131 | client->SendTextAsync(line); 132 | } 133 | 134 | // Disconnect the client 135 | std::cout << "Client disconnecting..."; 136 | client->DisconnectAndStop(); 137 | std::cout << "Done!" << std::endl; 138 | 139 | // Stop the Asio service 140 | std::cout << "Asio service stopping..."; 141 | service->Stop(); 142 | std::cout << "Done!" << std::endl; 143 | 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /examples/ws_chat_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ws_chat_server.cpp 3 | \brief WebSocket chat server example 4 | \author Ivan Shynkarenka 5 | \date 28.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/ws/ws_server.h" 12 | 13 | #include 14 | 15 | class ChatSession : public CppServer::WS::WSSession 16 | { 17 | public: 18 | using CppServer::WS::WSSession::WSSession; 19 | 20 | protected: 21 | void onWSConnected(const CppServer::HTTP::HTTPRequest& request) override 22 | { 23 | std::cout << "Chat WebSocket session with Id " << id() << " connected!" << std::endl; 24 | 25 | // Send invite message 26 | std::string message("Hello from WebSocket chat! Please send a message or '!' to disconnect the client!"); 27 | SendTextAsync(message); 28 | } 29 | 30 | void onWSDisconnected() override 31 | { 32 | std::cout << "Chat WebSocket session with Id " << id() << " disconnected!" << std::endl; 33 | } 34 | 35 | void onWSReceived(const void* buffer, size_t size) override 36 | { 37 | std::string message((const char*)buffer, size); 38 | std::cout << "Incoming: " << message << std::endl; 39 | 40 | // Multicast message to all connected sessions 41 | std::dynamic_pointer_cast(server())->MulticastText(message); 42 | 43 | // If the buffer starts with '!' the disconnect the current session 44 | if (message == "!") 45 | Close(); 46 | } 47 | 48 | void onError(int error, const std::string& category, const std::string& message) override 49 | { 50 | std::cout << "Chat WebSocket session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 51 | } 52 | }; 53 | 54 | class ChatServer : public CppServer::WS::WSServer 55 | { 56 | public: 57 | using CppServer::WS::WSServer::WSServer; 58 | 59 | protected: 60 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 61 | { 62 | return std::make_shared(std::dynamic_pointer_cast(server)); 63 | } 64 | 65 | protected: 66 | void onError(int error, const std::string& category, const std::string& message) override 67 | { 68 | std::cout << "Chat WebSocket server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 69 | } 70 | }; 71 | 72 | int main(int argc, char** argv) 73 | { 74 | // WebSocket server port 75 | int port = 8080; 76 | if (argc > 1) 77 | port = std::atoi(argv[1]); 78 | // WebSocket server content path 79 | std::string www = "../www/ws"; 80 | if (argc > 2) 81 | www = argv[2]; 82 | 83 | std::cout << "WebSocket server port: " << port << std::endl; 84 | std::cout << "WebSocket server static content path: " << www << std::endl; 85 | std::cout << "WebSocket server website: " << "http://localhost:" << port << "/chat/index.html" << std::endl; 86 | 87 | std::cout << std::endl; 88 | 89 | // Create a new Asio service 90 | auto service = std::make_shared(); 91 | 92 | // Start the Asio service 93 | std::cout << "Asio service starting..."; 94 | service->Start(); 95 | std::cout << "Done!" << std::endl; 96 | 97 | // Create a new WebSocket chat server 98 | auto server = std::make_shared(service, port); 99 | server->AddStaticContent(www, "/chat"); 100 | 101 | // Start the server 102 | std::cout << "Server starting..."; 103 | server->Start(); 104 | std::cout << "Done!" << std::endl; 105 | 106 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 107 | 108 | // Perform text input 109 | std::string line; 110 | while (getline(std::cin, line)) 111 | { 112 | if (line.empty()) 113 | break; 114 | 115 | // Restart the server 116 | if (line == "!") 117 | { 118 | std::cout << "Server restarting..."; 119 | server->Restart(); 120 | std::cout << "Done!" << std::endl; 121 | continue; 122 | } 123 | 124 | // Multicast admin message to all sessions 125 | line = "(admin) " + line; 126 | server->MulticastText(line); 127 | } 128 | 129 | // Stop the server 130 | std::cout << "Server stopping..."; 131 | server->Stop(); 132 | std::cout << "Done!" << std::endl; 133 | 134 | // Stop the Asio service 135 | std::cout << "Asio service stopping..."; 136 | service->Stop(); 137 | std::cout << "Done!" << std::endl; 138 | 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /examples/wss_chat_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file wss_chat_client.cpp 3 | \brief WebSocket secure chat client example 4 | \author Ivan Shynkarenka 5 | \date 22.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "asio_service.h" 10 | 11 | #include "server/ws/wss_client.h" 12 | #include "threads/thread.h" 13 | 14 | #include 15 | #include 16 | 17 | class ChatClient : public CppServer::WS::WSSClient 18 | { 19 | public: 20 | using CppServer::WS::WSSClient::WSSClient; 21 | 22 | void DisconnectAndStop() 23 | { 24 | _stop = true; 25 | CloseAsync(1000); 26 | while (IsConnected()) 27 | CppCommon::Thread::Yield(); 28 | } 29 | 30 | protected: 31 | void onWSConnecting(CppServer::HTTP::HTTPRequest& request) override 32 | { 33 | request.SetBegin("GET", "/"); 34 | request.SetHeader("Host", "localhost"); 35 | request.SetHeader("Origin", "https://localhost"); 36 | request.SetHeader("Upgrade", "websocket"); 37 | request.SetHeader("Connection", "Upgrade"); 38 | request.SetHeader("Sec-WebSocket-Key", CppCommon::Encoding::Base64Encode(ws_nonce())); 39 | request.SetHeader("Sec-WebSocket-Protocol", "chat, superchat"); 40 | request.SetHeader("Sec-WebSocket-Version", "13"); 41 | } 42 | 43 | void onWSConnected(const CppServer::HTTP::HTTPResponse& response) override 44 | { 45 | std::cout << "Chat WebSocket secure client connected a new session with Id " << id() << std::endl; 46 | } 47 | 48 | void onWSDisconnected() override 49 | { 50 | std::cout << "Chat WebSocket secure client disconnected a session with Id " << id() << std::endl; 51 | } 52 | 53 | void onWSReceived(const void* buffer, size_t size) override 54 | { 55 | std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl; 56 | } 57 | 58 | void onDisconnected() override 59 | { 60 | WSSClient::onDisconnected(); 61 | 62 | // Wait for a while... 63 | CppCommon::Thread::Sleep(1000); 64 | 65 | // Try to connect again 66 | if (!_stop) 67 | ConnectAsync(); 68 | } 69 | 70 | void onError(int error, const std::string& category, const std::string& message) override 71 | { 72 | std::cout << "Chat WebSocket secure client caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 73 | } 74 | 75 | private: 76 | std::atomic _stop{false}; 77 | }; 78 | 79 | int main(int argc, char** argv) 80 | { 81 | // WebSocket server address 82 | std::string address = "127.0.0.1"; 83 | if (argc > 1) 84 | address = argv[1]; 85 | 86 | // WebSocket server port 87 | int port = 8443; 88 | if (argc > 2) 89 | port = std::atoi(argv[2]); 90 | 91 | std::cout << "WebSocket secure server address: " << address << std::endl; 92 | std::cout << "WebSocket secure server port: " << port << std::endl; 93 | 94 | std::cout << std::endl; 95 | 96 | // Create a new Asio service 97 | auto service = std::make_shared(); 98 | 99 | // Start the Asio service 100 | std::cout << "Asio service starting..."; 101 | service->Start(); 102 | std::cout << "Done!" << std::endl; 103 | 104 | // Create and prepare a new SSL client context 105 | auto context = std::make_shared(asio::ssl::context::tlsv13); 106 | context->set_default_verify_paths(); 107 | context->set_root_certs(); 108 | context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert); 109 | context->load_verify_file("../tools/certificates/ca.pem"); 110 | 111 | // Create a new WebSocket chat client 112 | auto client = std::make_shared(service, context, address, port); 113 | 114 | // Connect the client 115 | std::cout << "Client connecting..."; 116 | client->ConnectAsync(); 117 | std::cout << "Done!" << std::endl; 118 | 119 | std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl; 120 | 121 | // Perform text input 122 | std::string line; 123 | while (getline(std::cin, line)) 124 | { 125 | if (line.empty()) 126 | break; 127 | 128 | // Reconnect the client 129 | if (line == "!") 130 | { 131 | std::cout << "Client reconnecting..."; 132 | client->IsConnected() ? client->ReconnectAsync() : client->ConnectAsync(); 133 | std::cout << "Done!" << std::endl; 134 | continue; 135 | } 136 | 137 | // Send the entered text to the chat server 138 | client->SendTextAsync(line); 139 | } 140 | 141 | // Disconnect the client 142 | std::cout << "Client disconnecting..."; 143 | client->DisconnectAndStop(); 144 | std::cout << "Done!" << std::endl; 145 | 146 | // Stop the Asio service 147 | std::cout << "Asio service stopping..."; 148 | service->Stop(); 149 | std::cout << "Done!" << std::endl; 150 | 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /images/multicast.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/multicast.ai -------------------------------------------------------------------------------- /images/multicast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/multicast.png -------------------------------------------------------------------------------- /images/openapi-http.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/openapi-http.png -------------------------------------------------------------------------------- /images/openapi-https.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/openapi-https.png -------------------------------------------------------------------------------- /images/round-trip.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/round-trip.ai -------------------------------------------------------------------------------- /images/round-trip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/round-trip.png -------------------------------------------------------------------------------- /images/ws-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/ws-chat.png -------------------------------------------------------------------------------- /images/wss-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/images/wss-chat.png -------------------------------------------------------------------------------- /include/server/asio/asio.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file asio.h 3 | \brief Asio C++ Library definition 4 | \author Ivan Shynkarenka 5 | \date 14.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_ASIO_H 10 | #define CPPSERVER_ASIO_H 11 | 12 | #include 13 | 14 | #if defined(__clang__) 15 | #pragma clang system_header 16 | #elif defined(__GNUC__) 17 | #pragma GCC system_header 18 | #elif defined(_MSC_VER) 19 | #pragma system_header 20 | #endif 21 | 22 | #if defined(__CYGWIN__) 23 | 24 | #include 25 | #include 26 | 27 | #else 28 | 29 | #define ASIO_STANDALONE 30 | #define ASIO_SEPARATE_COMPILATION 31 | #define ASIO_NO_WIN32_LEAN_AND_MEAN 32 | 33 | #if defined(_MSC_VER) 34 | #pragma warning(push) 35 | #pragma warning(disable: 4459) // C4459: declaration of 'identifier' hides global declaration 36 | #endif 37 | 38 | #include 39 | #include 40 | 41 | #if defined(_MSC_VER) 42 | #pragma warning(pop) 43 | #endif 44 | 45 | #if defined(_WIN32) || defined(_WIN64) 46 | #undef DELETE 47 | #undef ERROR 48 | #undef Yield 49 | #undef min 50 | #undef max 51 | #undef uuid_t 52 | #endif 53 | 54 | #endif 55 | 56 | namespace CppServer { 57 | 58 | /*! 59 | \namespace CppServer::Asio 60 | \brief Asio definitions 61 | */ 62 | namespace Asio { 63 | 64 | //! Internet protocol 65 | enum class InternetProtocol 66 | { 67 | IPv4, //!< Internet Protocol version 4 68 | IPv6 //!< Internet Protocol version 6 69 | }; 70 | 71 | //! Stream output: Internet protocol 72 | /*! 73 | \param stream - Output stream 74 | \param protocol - Internet protocol 75 | \return Output stream 76 | */ 77 | template 78 | TOutputStream& operator<<(TOutputStream& stream, InternetProtocol protocol); 79 | 80 | } // namespace Asio 81 | } // namespace CppServer 82 | 83 | #include "asio.inl" 84 | 85 | #endif // CPPSERVER_ASIO_H 86 | -------------------------------------------------------------------------------- /include/server/asio/asio.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file asio.inl 3 | \brief Asio C++ Library inline implementation 4 | \author Ivan Shynkarenka 5 | \date 14.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppServer { 10 | namespace Asio { 11 | 12 | template 13 | inline TOutputStream& operator<<(TOutputStream& stream, InternetProtocol protocol) 14 | { 15 | switch (protocol) 16 | { 17 | case InternetProtocol::IPv4: 18 | stream << "IPv4"; 19 | break; 20 | case InternetProtocol::IPv6: 21 | stream << "IPv6"; 22 | break; 23 | default: 24 | stream << ""; 25 | break; 26 | } 27 | return stream; 28 | } 29 | 30 | } // namespace Asio 31 | } // namespace CppServer 32 | -------------------------------------------------------------------------------- /include/server/asio/memory.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file memory.inl 3 | \brief Asio memory manager inline implementation 4 | \author Ivan Shynkarenka 5 | \date 16.02.2018 6 | \copyright MIT License 7 | */ 8 | 9 | namespace CppServer { 10 | namespace Asio { 11 | 12 | inline void* HandlerStorage::allocate(size_t size) 13 | { 14 | // Check if the storage is not already used and has enough capacity 15 | if (!_in_use && (size < sizeof(_storage))) 16 | { 17 | _in_use = true; 18 | return &_storage; 19 | } 20 | 21 | // Otherwise allocate memory in the heap 22 | return ::operator new(size); 23 | } 24 | 25 | inline void HandlerStorage::deallocate(void* ptr) 26 | { 27 | // Free storage if memory block was allocated from it 28 | if (ptr == &_storage) 29 | { 30 | _in_use = false; 31 | return; 32 | } 33 | 34 | // Otherwise free memory in the heap 35 | ::operator delete(ptr); 36 | } 37 | 38 | template 39 | inline AllocateHandler make_alloc_handler(HandlerStorage& storage, THandler handler) 40 | { 41 | return AllocateHandler(storage, handler); 42 | } 43 | 44 | } // namespace Asio 45 | } // namespace CppServer 46 | -------------------------------------------------------------------------------- /include/server/asio/ssl_context.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ssl_context.h 3 | \brief SSL context definition 4 | \author Ivan Shynkarenka 5 | \date 12.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_ASIO_SSL_CONTEXT_H 10 | #define CPPSERVER_ASIO_SSL_CONTEXT_H 11 | 12 | #include "service.h" 13 | 14 | namespace CppServer { 15 | namespace Asio { 16 | 17 | //! SSL context 18 | /*! 19 | SSL context is used to handle and validate certificates in SSL clients and servers. 20 | 21 | Thread-safe. 22 | */ 23 | class SSLContext : public asio::ssl::context 24 | { 25 | public: 26 | using asio::ssl::context::context; 27 | 28 | SSLContext(const SSLContext&) = delete; 29 | SSLContext(SSLContext&&) = delete; 30 | ~SSLContext() = default; 31 | 32 | SSLContext& operator=(const SSLContext&) = delete; 33 | SSLContext& operator=(SSLContext&&) = delete; 34 | 35 | //! Configures the context to use system root certificates 36 | void set_root_certs(); 37 | }; 38 | 39 | } // namespace Asio 40 | } // namespace CppServer 41 | 42 | #endif // CPPSERVER_ASIO_SSL_CONTEXT_H 43 | -------------------------------------------------------------------------------- /include/server/asio/tcp_resolver.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file tcp_resolver.h 3 | \brief TCP resolver definition 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_ASIO_TCP_RESOLVER_H 10 | #define CPPSERVER_ASIO_TCP_RESOLVER_H 11 | 12 | #include "service.h" 13 | 14 | namespace CppServer { 15 | namespace Asio { 16 | 17 | //! TCP resolver 18 | /*! 19 | TCP resolver is used to resolve DNS while connecting TCP/SSL clients. 20 | 21 | Thread-safe. 22 | */ 23 | class TCPResolver 24 | { 25 | public: 26 | //! Initialize resolver with a given Asio service 27 | /*! 28 | \param service - Asio service 29 | */ 30 | TCPResolver(const std::shared_ptr& service); 31 | TCPResolver(const TCPResolver&) = delete; 32 | TCPResolver(TCPResolver&&) = delete; 33 | virtual ~TCPResolver() { Cancel(); } 34 | 35 | TCPResolver& operator=(const TCPResolver&) = delete; 36 | TCPResolver& operator=(TCPResolver&&) = delete; 37 | 38 | //! Get the Asio service 39 | std::shared_ptr& service() noexcept { return _service; } 40 | //! Get the Asio IO service 41 | std::shared_ptr& io_service() noexcept { return _io_service; } 42 | //! Get the Asio service strand for serialized handler execution 43 | asio::io_service::strand& strand() noexcept { return _strand; } 44 | //! Get the TCP resolver 45 | asio::ip::tcp::resolver& resolver() noexcept { return _resolver; } 46 | 47 | //! Cancel any asynchronous operations that are waiting on the resolver 48 | virtual void Cancel() { _resolver.cancel(); } 49 | 50 | private: 51 | // Asio service 52 | std::shared_ptr _service; 53 | // Asio IO service 54 | std::shared_ptr _io_service; 55 | // Asio service strand for serialized handler execution 56 | asio::io_service::strand _strand; 57 | bool _strand_required; 58 | // TCP resolver 59 | asio::ip::tcp::resolver _resolver; 60 | }; 61 | 62 | } // namespace Asio 63 | } // namespace CppServer 64 | 65 | #endif // CPPSERVER_ASIO_TCP_RESOLVER_H 66 | -------------------------------------------------------------------------------- /include/server/asio/udp_resolver.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file udp_resolver.h 3 | \brief UDP resolver definition 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_ASIO_UDP_RESOLVER_H 10 | #define CPPSERVER_ASIO_UDP_RESOLVER_H 11 | 12 | #include "service.h" 13 | 14 | namespace CppServer { 15 | namespace Asio { 16 | 17 | //! UDP resolver 18 | /*! 19 | UDP resolver is used to resolve DNS while connecting UDP clients. 20 | 21 | Thread-safe. 22 | */ 23 | class UDPResolver 24 | { 25 | public: 26 | //! Initialize resolver with a given Asio service 27 | /*! 28 | \param service - Asio service 29 | */ 30 | UDPResolver(const std::shared_ptr& service); 31 | UDPResolver(const UDPResolver&) = delete; 32 | UDPResolver(UDPResolver&&) = delete; 33 | virtual ~UDPResolver() { Cancel(); } 34 | 35 | UDPResolver& operator=(const UDPResolver&) = delete; 36 | UDPResolver& operator=(UDPResolver&&) = delete; 37 | 38 | //! Get the Asio service 39 | std::shared_ptr& service() noexcept { return _service; } 40 | //! Get the Asio IO service 41 | std::shared_ptr& io_service() noexcept { return _io_service; } 42 | //! Get the Asio service strand for serialized handler execution 43 | asio::io_service::strand& strand() noexcept { return _strand; } 44 | //! Get the UDP resolver 45 | asio::ip::udp::resolver& resolver() noexcept { return _resolver; } 46 | 47 | //! Cancel any asynchronous operations that are waiting on the resolver 48 | virtual void Cancel() { _resolver.cancel(); } 49 | 50 | private: 51 | // Asio service 52 | std::shared_ptr _service; 53 | // Asio IO service 54 | std::shared_ptr _io_service; 55 | // Asio service strand for serialized handler execution 56 | asio::io_service::strand _strand; 57 | bool _strand_required; 58 | // UDP resolver 59 | asio::ip::udp::resolver _resolver; 60 | }; 61 | 62 | } // namespace Asio 63 | } // namespace CppServer 64 | 65 | #endif // CPPSERVER_ASIO_UDP_RESOLVER_H 66 | -------------------------------------------------------------------------------- /include/server/http/http.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http.h 3 | \brief HTTP C++ Library definition 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_HTTP_H 10 | #define CPPSERVER_HTTP_H 11 | 12 | namespace CppServer { 13 | 14 | /*! 15 | \namespace CppServer::HTTP 16 | \brief HTTP definitions 17 | */ 18 | namespace HTTP { 19 | 20 | } // namespace HTTP 21 | } // namespace CppServer 22 | 23 | #endif // CPPSERVER_HTTP_H 24 | -------------------------------------------------------------------------------- /include/server/http/http_request.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_request.inl 3 | \brief HTTP request inline implementation 4 | \author Ivan Shynkarenka 5 | \date 07.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #if defined(FMT_VERSION) 10 | template <> struct fmt::formatter : ostream_formatter {}; 11 | #endif 12 | 13 | //! \cond DOXYGEN_SKIP 14 | template <> 15 | struct std::hash 16 | { 17 | typedef CppServer::HTTP::HTTPRequest argument_type; 18 | typedef size_t result_type; 19 | 20 | result_type operator() (const argument_type& value) const 21 | { 22 | result_type result = 17; 23 | result = result * 31 + std::hash()(value.cache()); 24 | return result; 25 | } 26 | }; 27 | //! \endcond 28 | -------------------------------------------------------------------------------- /include/server/http/http_response.inl: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_response.inl 3 | \brief HTTP response inline implementation 4 | \author Ivan Shynkarenka 5 | \date 15.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #if defined(FMT_VERSION) 10 | template <> struct fmt::formatter : ostream_formatter {}; 11 | #endif 12 | 13 | //! \cond DOXYGEN_SKIP 14 | template <> 15 | struct std::hash 16 | { 17 | typedef CppServer::HTTP::HTTPResponse argument_type; 18 | typedef size_t result_type; 19 | 20 | result_type operator() (const argument_type& value) const 21 | { 22 | result_type result = 17; 23 | result = result * 31 + std::hash()(value.cache()); 24 | return result; 25 | } 26 | }; 27 | //! \endcond 28 | -------------------------------------------------------------------------------- /include/server/http/http_server.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_server.h 3 | \brief HTTP server definition 4 | \author Ivan Shynkarenka 5 | \date 30.04.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_HTTP_HTTP_SERVER_H 10 | #define CPPSERVER_HTTP_HTTP_SERVER_H 11 | 12 | #include "http_session.h" 13 | 14 | #include "cache/filecache.h" 15 | #include "server/asio/tcp_server.h" 16 | 17 | namespace CppServer { 18 | namespace HTTP { 19 | 20 | //! HTTP server 21 | /*! 22 | HTTP server is used to create HTTP Web server and 23 | communicate with clients using HTTP protocol. 24 | It allows to receive GET, POST, PUT, DELETE requests and 25 | send HTTP responses. 26 | 27 | Thread-safe. 28 | */ 29 | class HTTPServer : public Asio::TCPServer 30 | { 31 | public: 32 | using TCPServer::TCPServer; 33 | 34 | HTTPServer(const HTTPServer&) = delete; 35 | HTTPServer(HTTPServer&&) = delete; 36 | virtual ~HTTPServer() = default; 37 | 38 | HTTPServer& operator=(const HTTPServer&) = delete; 39 | HTTPServer& operator=(HTTPServer&&) = delete; 40 | 41 | //! Get the static content cache 42 | CppCommon::FileCache& cache() noexcept { return _cache; } 43 | const CppCommon::FileCache& cache() const noexcept { return _cache; } 44 | 45 | //! Add static content cache 46 | /*! 47 | \param path - Static content path 48 | \param prefix - Cache prefix (default is "/") 49 | \param timeout - Refresh cache timeout (default is 1 hour) 50 | */ 51 | void AddStaticContent(const CppCommon::Path& path, const std::string& prefix = "/", const CppCommon::Timespan& timeout = CppCommon::Timespan::hours(1)); 52 | //! Remove static content cache 53 | /*! 54 | \param path - Static content path 55 | */ 56 | void RemoveStaticContent(const CppCommon::Path& path) { _cache.remove_path(path); } 57 | //! Clear static content cache 58 | void ClearStaticContent() { _cache.clear(); } 59 | 60 | //! Watchdog the static content cache 61 | void Watchdog(const CppCommon::UtcTimestamp& utc = CppCommon::UtcTimestamp()) { _cache.watchdog(utc); } 62 | 63 | protected: 64 | std::shared_ptr CreateSession(const std::shared_ptr& server) override { return std::make_shared(std::dynamic_pointer_cast(server)); } 65 | 66 | private: 67 | // Static content cache 68 | CppCommon::FileCache _cache; 69 | }; 70 | 71 | /*! \example http_server.cpp HTTP server example */ 72 | 73 | } // namespace HTTP 74 | } // namespace CppServer 75 | 76 | #endif // CPPSERVER_HTTP_HTTP_SERVER_H 77 | -------------------------------------------------------------------------------- /include/server/http/https_server.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file https_server.h 3 | \brief HTTPS server definition 4 | \author Ivan Shynkarenka 5 | \date 30.04.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_HTTP_HTTPS_SERVER_H 10 | #define CPPSERVER_HTTP_HTTPS_SERVER_H 11 | 12 | #include "https_session.h" 13 | 14 | #include "cache/filecache.h" 15 | #include "server/asio/ssl_server.h" 16 | 17 | namespace CppServer { 18 | namespace HTTP { 19 | 20 | //! HTTPS server 21 | /*! 22 | HTTPS server is used to create secured HTTPS Web server and 23 | communicate with clients using secure HTTPS protocol. 24 | It allows to receive GET, POST, PUT, DELETE requests and 25 | send HTTP responses. 26 | 27 | Thread-safe. 28 | */ 29 | class HTTPSServer : public Asio::SSLServer 30 | { 31 | public: 32 | using SSLServer::SSLServer; 33 | 34 | HTTPSServer(const HTTPSServer&) = delete; 35 | HTTPSServer(HTTPSServer&&) = delete; 36 | virtual ~HTTPSServer() = default; 37 | 38 | HTTPSServer& operator=(const HTTPSServer&) = delete; 39 | HTTPSServer& operator=(HTTPSServer&&) = delete; 40 | 41 | //! Get the static content cache 42 | CppCommon::FileCache& cache() noexcept { return _cache; } 43 | const CppCommon::FileCache& cache() const noexcept { return _cache; } 44 | 45 | //! Add static content cache 46 | /*! 47 | \param path - Static content path 48 | \param prefix - Cache prefix (default is "/") 49 | \param timeout - Refresh cache timeout (default is 1 hour) 50 | */ 51 | void AddStaticContent(const CppCommon::Path& path, const std::string& prefix = "/", const CppCommon::Timespan& timeout = CppCommon::Timespan::hours(1)); 52 | //! Remove static content cache 53 | /*! 54 | \param path - Static content path 55 | */ 56 | void RemoveStaticContent(const CppCommon::Path& path) { _cache.remove_path(path); } 57 | //! Clear static content cache 58 | void ClearStaticContent() { _cache.clear(); } 59 | 60 | //! Watchdog the static content cache 61 | void Watchdog(const CppCommon::UtcTimestamp& utc = CppCommon::UtcTimestamp()) { _cache.watchdog(utc); } 62 | 63 | protected: 64 | std::shared_ptr CreateSession(const std::shared_ptr& server) override { return std::make_shared(std::dynamic_pointer_cast(server)); } 65 | 66 | private: 67 | // Static content cache 68 | CppCommon::FileCache _cache; 69 | }; 70 | 71 | /*! \example https_server.cpp HTTPS server example */ 72 | 73 | } // namespace HTTP 74 | } // namespace CppServer 75 | 76 | #endif // CPPSERVER_HTTP_HTTPS_SERVER_H 77 | -------------------------------------------------------------------------------- /include/server/version.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file version.h 3 | \brief Version definition 4 | \author Ivan Shynkarenka 5 | \date 14.12.2016 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_VERSION_H 10 | #define CPPSERVER_VERSION_H 11 | 12 | /*! \mainpage C++ Server Library 13 | 14 | C++ Server Library provides functionality to create different kind of 15 | client/server solutions. 16 | 17 | This document contains CppServer API references. 18 | 19 | Library description, features, requirements and usage examples can be find on 20 | GitHub: https://github.com/chronoxor/CppServer 21 | 22 | */ 23 | 24 | /*! 25 | \namespace CppServer 26 | \brief C++ Server project definitions 27 | */ 28 | namespace CppServer { 29 | 30 | //! Project version 31 | const char version[] = "1.0.5.0"; 32 | 33 | } // namespace CppServer 34 | 35 | #endif // CPPSERVER_VERSION_H 36 | -------------------------------------------------------------------------------- /include/server/ws/ws_server.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ws_server.h 3 | \brief WebSocket server definition 4 | \author Ivan Shynkarenka 5 | \date 27.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_HTTP_WS_SERVER_H 10 | #define CPPSERVER_HTTP_WS_SERVER_H 11 | 12 | #include "ws_session.h" 13 | 14 | #include "server/http/http_server.h" 15 | 16 | namespace CppServer { 17 | namespace WS { 18 | 19 | //! WebSocket server 20 | /*! 21 | WebSocket server is used to communicate with clients using 22 | WebSocket protocol. 23 | 24 | https://en.wikipedia.org/wiki/WebSocket 25 | 26 | Thread-safe. 27 | */ 28 | class WSServer : public HTTP::HTTPServer, protected WebSocket 29 | { 30 | public: 31 | using HTTPServer::HTTPServer; 32 | 33 | WSServer(const WSServer&) = delete; 34 | WSServer(WSServer&&) = delete; 35 | virtual ~WSServer() = default; 36 | 37 | WSServer& operator=(const WSServer&) = delete; 38 | WSServer& operator=(WSServer&&) = delete; 39 | 40 | // WebSocket connection methods 41 | virtual bool CloseAll() { return CloseAll(0, nullptr, 0); } 42 | virtual bool CloseAll(int status) { return CloseAll(status, nullptr, 0); } 43 | virtual bool CloseAll(int status, const void* buffer, size_t size); 44 | virtual bool CloseAll(int status, std::string_view text); 45 | 46 | //! Multicast data to all connected WebSocket sessions 47 | bool Multicast(const void* buffer, size_t size) override; 48 | 49 | // WebSocket multicast text methods 50 | size_t MulticastText(const void* buffer, size_t size) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_TEXT, false, buffer, size); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 51 | size_t MulticastText(std::string_view text) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_TEXT, false, text.data(), text.size()); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 52 | 53 | // WebSocket multicast binary methods 54 | size_t MulticastBinary(const void* buffer, size_t size) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_BINARY, false, buffer, size); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 55 | size_t MulticastBinary(std::string_view text) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_BINARY, false, text.data(), text.size()); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 56 | 57 | // WebSocket multicast ping methods 58 | size_t MulticastPing(const void* buffer, size_t size) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_PING, false, buffer, size); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 59 | size_t MulticastPing(std::string_view text) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_PING, false, text.data(), text.size()); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 60 | 61 | protected: 62 | std::shared_ptr CreateSession(const std::shared_ptr& server) override { return std::make_shared(std::dynamic_pointer_cast(server)); } 63 | }; 64 | 65 | /*! \example ws_chat_server.cpp WebSocket chat server example */ 66 | 67 | } // namespace WS 68 | } // namespace CppServer 69 | 70 | #endif // CPPSERVER_HTTP_WS_SERVER_H 71 | -------------------------------------------------------------------------------- /include/server/ws/wss_server.h: -------------------------------------------------------------------------------- 1 | /*! 2 | \file wss_server.h 3 | \brief WebSocket secure server definition 4 | \author Ivan Shynkarenka 5 | \date 28.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #ifndef CPPSERVER_HTTP_WSS_SERVER_H 10 | #define CPPSERVER_HTTP_WSS_SERVER_H 11 | 12 | #include "wss_session.h" 13 | 14 | #include "server/http/https_server.h" 15 | 16 | namespace CppServer { 17 | namespace WS { 18 | 19 | //! WebSocket secure server 20 | /*! 21 | WebSocket secure server is used to communicate with clients using 22 | WebSocket secure protocol. 23 | 24 | https://en.wikipedia.org/wiki/WebSocket 25 | 26 | Thread-safe. 27 | */ 28 | class WSSServer : public HTTP::HTTPSServer, protected WebSocket 29 | { 30 | public: 31 | using HTTPSServer::HTTPSServer; 32 | 33 | WSSServer(const WSSServer&) = delete; 34 | WSSServer(WSSServer&&) = delete; 35 | virtual ~WSSServer() = default; 36 | 37 | WSSServer& operator=(const WSSServer&) = delete; 38 | WSSServer& operator=(WSSServer&&) = delete; 39 | 40 | // WebSocket connection methods 41 | virtual bool CloseAll() { return CloseAll(0, nullptr, 0); } 42 | virtual bool CloseAll(int status) { return CloseAll(status, nullptr, 0); } 43 | virtual bool CloseAll(int status, const void* buffer, size_t size); 44 | virtual bool CloseAll(int status, std::string_view text); 45 | 46 | //! Multicast data to all connected WebSocket sessions 47 | bool Multicast(const void* buffer, size_t size) override; 48 | 49 | // WebSocket multicast text methods 50 | size_t MulticastText(const void* buffer, size_t size) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_TEXT, false, buffer, size); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 51 | size_t MulticastText(std::string_view text) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_TEXT, false, text.data(), text.size()); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 52 | 53 | // WebSocket multicast binary methods 54 | size_t MulticastBinary(const void* buffer, size_t size) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_BINARY, false, buffer, size); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 55 | size_t MulticastBinary(std::string_view text) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_BINARY, false, text.data(), text.size()); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 56 | 57 | // WebSocket multicast ping methods 58 | size_t MulticastPing(const void* buffer, size_t size) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_PING, false, buffer, size); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 59 | size_t MulticastPing(std::string_view text) { std::scoped_lock locker(_ws_send_lock); PrepareSendFrame(WS_FIN | WS_PING, false, text.data(), text.size()); return Multicast(_ws_send_buffer.data(), _ws_send_buffer.size()); } 60 | 61 | protected: 62 | std::shared_ptr CreateSession(const std::shared_ptr& server) override { return std::make_shared(std::dynamic_pointer_cast(server)); } 63 | }; 64 | 65 | /*! \example wss_chat_server.cpp WebSocket secure chat server example */ 66 | 67 | } // namespace WS 68 | } // namespace CppServer 69 | 70 | #endif // CPPSERVER_HTTP_WSS_SERVER_H 71 | -------------------------------------------------------------------------------- /modules/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include("asio.cmake") 2 | include("Catch2.cmake") 3 | include("cpp-optparse.cmake") 4 | include("CppBenchmark.cmake") 5 | include("CppCommon.cmake") 6 | -------------------------------------------------------------------------------- /modules/Catch2.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET Catch2) 2 | 3 | # Module library 4 | file(GLOB SOURCE_FILES "Catch2/extras/catch_amalgamated.cpp") 5 | add_library(Catch2 ${SOURCE_FILES}) 6 | target_include_directories(Catch2 PUBLIC "Catch2/extras") 7 | 8 | # Module folder 9 | set_target_properties(Catch2 PROPERTIES FOLDER "modules/Catch2") 10 | 11 | endif() 12 | -------------------------------------------------------------------------------- /modules/CppBenchmark.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET cppbenchmark) 2 | 3 | # Module flag 4 | set(CPPBENCHMARK_MODULE Y) 5 | 6 | # Module subdirectory 7 | add_subdirectory("CppBenchmark") 8 | 9 | # Module folder 10 | set_target_properties(cppbenchmark PROPERTIES FOLDER "modules/CppBenchmark") 11 | 12 | endif() 13 | -------------------------------------------------------------------------------- /modules/CppCommon.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET cppcommon) 2 | 3 | # Module flag 4 | set(CPPCOMMON_MODULE Y) 5 | 6 | # Module subdirectory 7 | add_subdirectory("CppCommon") 8 | 9 | # Module folder 10 | set_target_properties(cppcommon PROPERTIES FOLDER "modules/CppCommon") 11 | 12 | endif() 13 | -------------------------------------------------------------------------------- /modules/asio.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET asio) 2 | 3 | # Module library 4 | file(GLOB SOURCE_FILES "asio/asio/src/*.cpp") 5 | add_library(asio ${SOURCE_FILES}) 6 | if(MSVC) 7 | set_target_properties(asio PROPERTIES COMPILE_FLAGS "${PEDANTIC_COMPILE_FLAGS}") 8 | else() 9 | set_target_properties(asio PROPERTIES COMPILE_FLAGS "${PEDANTIC_COMPILE_FLAGS} -Wno-shadow") 10 | endif() 11 | target_compile_definitions(asio PRIVATE ASIO_STANDALONE ASIO_SEPARATE_COMPILATION) 12 | target_include_directories(asio PUBLIC "asio/asio/include" PUBLIC ${OPENSSL_INCLUDE_DIR}) 13 | target_link_libraries(asio ${OPENSSL_LIBRARIES}) 14 | 15 | # Module folder 16 | set_target_properties(asio PROPERTIES FOLDER "modules/asio") 17 | 18 | endif() 19 | -------------------------------------------------------------------------------- /modules/cpp-optparse.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET cpp-optparse) 2 | 3 | # Module library 4 | file(GLOB SOURCE_FILES "cpp-optparse/OptionParser.cpp") 5 | add_library(cpp-optparse ${SOURCE_FILES}) 6 | if(MSVC) 7 | # C4244: 'conversion' conversion from 'type1' to 'type2', possible loss of data 8 | # C4996:
is removed in C++20 9 | set_target_properties(cpp-optparse PROPERTIES COMPILE_FLAGS "${PEDANTIC_COMPILE_FLAGS} /wd4244 /wd4996") 10 | else() 11 | set_target_properties(cpp-optparse PROPERTIES COMPILE_FLAGS "${PEDANTIC_COMPILE_FLAGS}") 12 | endif() 13 | target_include_directories(cpp-optparse PUBLIC "cpp-optparse") 14 | 15 | # Module folder 16 | set_target_properties(cpp-optparse PROPERTIES FOLDER "modules/cpp-optparse") 17 | 18 | endif() 19 | -------------------------------------------------------------------------------- /performance/http_trace_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 02.05.2019 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/http/http_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | using namespace CppServer::HTTP; 16 | 17 | class HTTPTraceSession : public HTTPSession 18 | { 19 | public: 20 | using HTTPSession::HTTPSession; 21 | 22 | protected: 23 | void onReceivedRequest(const HTTPRequest& request) override 24 | { 25 | // Process HTTP request methods 26 | if (request.method() == "TRACE") 27 | SendResponseAsync(response().MakeTraceResponse(request.cache())); 28 | else 29 | SendResponseAsync(response().MakeErrorResponse("Unsupported HTTP method: " + std::string(request.method()))); 30 | } 31 | 32 | void onReceivedRequestError(const HTTPRequest& request, const std::string& error) override 33 | { 34 | std::cout << "Request error: " << error << std::endl; 35 | } 36 | 37 | void onError(int error, const std::string& category, const std::string& message) override 38 | { 39 | std::cout << "HTTP Trace session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 40 | } 41 | }; 42 | 43 | class HTTPTraceServer : public HTTPServer 44 | { 45 | public: 46 | using HTTPServer::HTTPServer; 47 | 48 | protected: 49 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 50 | { 51 | return std::make_shared(std::dynamic_pointer_cast(server)); 52 | } 53 | 54 | protected: 55 | void onError(int error, const std::string& category, const std::string& message) override 56 | { 57 | std::cout << "HTTP Trace server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 58 | } 59 | }; 60 | 61 | int main(int argc, char** argv) 62 | { 63 | auto parser = optparse::OptionParser().version("1.0.0.0"); 64 | 65 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(8080).help("Server port. Default: %default"); 66 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 67 | 68 | optparse::Values options = parser.parse_args(argc, argv); 69 | 70 | // Print help 71 | if (options.get("help")) 72 | { 73 | parser.print_help(); 74 | return 0; 75 | } 76 | 77 | // Server port 78 | int port = options.get("port"); 79 | int threads = options.get("threads"); 80 | 81 | std::cout << "Server port: " << port << std::endl; 82 | std::cout << "Working threads: " << threads << std::endl; 83 | 84 | std::cout << std::endl; 85 | 86 | // Create a new Asio service 87 | auto service = std::make_shared(threads); 88 | 89 | // Start the Asio service 90 | std::cout << "Asio service starting..."; 91 | service->Start(); 92 | std::cout << "Done!" << std::endl; 93 | 94 | // Create a new HTTP Trace server 95 | auto server = std::make_shared(service, port); 96 | // server->SetupNoDelay(true); 97 | server->SetupReuseAddress(true); 98 | server->SetupReusePort(true); 99 | 100 | // Start the server 101 | std::cout << "Server starting..."; 102 | server->Start(); 103 | std::cout << "Done!" << std::endl; 104 | 105 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 106 | 107 | // Perform text input 108 | std::string line; 109 | while (getline(std::cin, line)) 110 | { 111 | if (line.empty()) 112 | break; 113 | 114 | // Restart the server 115 | if (line == "!") 116 | { 117 | std::cout << "Server restarting..."; 118 | server->Restart(); 119 | std::cout << "Done!" << std::endl; 120 | continue; 121 | } 122 | } 123 | 124 | // Stop the server 125 | std::cout << "Server stopping..."; 126 | server->Stop(); 127 | std::cout << "Done!" << std::endl; 128 | 129 | // Stop the Asio service 130 | std::cout << "Asio service stopping..."; 131 | service->Stop(); 132 | std::cout << "Done!" << std::endl; 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /performance/https_trace_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 02.05.2019 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/http/https_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | using namespace CppServer::HTTP; 16 | 17 | class HTTPSTraceSession : public HTTPSSession 18 | { 19 | public: 20 | using HTTPSSession::HTTPSSession; 21 | 22 | protected: 23 | void onReceivedRequest(const HTTPRequest& request) override 24 | { 25 | // Process HTTP request methods 26 | if (request.method() == "TRACE") 27 | SendResponseAsync(response().MakeTraceResponse(request.cache())); 28 | else 29 | SendResponseAsync(response().MakeErrorResponse("Unsupported HTTP method: " + std::string(request.method()))); 30 | } 31 | 32 | void onReceivedRequestError(const HTTPRequest& request, const std::string& error) override 33 | { 34 | std::cout << "Request error: " << error << std::endl; 35 | } 36 | 37 | void onError(int error, const std::string& category, const std::string& message) override 38 | { 39 | std::cout << "HTTPS Trace session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 40 | } 41 | }; 42 | 43 | class HTTPSTraceServer : public HTTPSServer 44 | { 45 | public: 46 | using HTTPSServer::HTTPSServer; 47 | 48 | protected: 49 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 50 | { 51 | return std::make_shared(std::dynamic_pointer_cast(server)); 52 | } 53 | 54 | protected: 55 | void onError(int error, const std::string& category, const std::string& message) override 56 | { 57 | std::cout << "HTTPS Trace server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 58 | } 59 | }; 60 | 61 | int main(int argc, char** argv) 62 | { 63 | auto parser = optparse::OptionParser().version("1.0.0.0"); 64 | 65 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(8443).help("Server port. Default: %default"); 66 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 67 | 68 | optparse::Values options = parser.parse_args(argc, argv); 69 | 70 | // Print help 71 | if (options.get("help")) 72 | { 73 | parser.print_help(); 74 | return 0; 75 | } 76 | 77 | // Server port 78 | int port = options.get("port"); 79 | int threads = options.get("threads"); 80 | 81 | std::cout << "Server port: " << port << std::endl; 82 | std::cout << "Working threads: " << threads << std::endl; 83 | 84 | std::cout << std::endl; 85 | 86 | // Create a new Asio service 87 | auto service = std::make_shared(threads); 88 | 89 | // Start the Asio service 90 | std::cout << "Asio service starting..."; 91 | service->Start(); 92 | std::cout << "Done!" << std::endl; 93 | 94 | // Create and prepare a new SSL server context 95 | auto context = std::make_shared(asio::ssl::context::tlsv13); 96 | context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; }); 97 | context->use_certificate_chain_file("../tools/certificates/server.pem"); 98 | context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem); 99 | context->use_tmp_dh_file("../tools/certificates/dh4096.pem"); 100 | 101 | // Create a new HTTPS Trace server 102 | auto server = std::make_shared(service, context, port); 103 | // server->SetupNoDelay(true); 104 | server->SetupReuseAddress(true); 105 | server->SetupReusePort(true); 106 | 107 | // Start the server 108 | std::cout << "Server starting..."; 109 | server->Start(); 110 | std::cout << "Done!" << std::endl; 111 | 112 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 113 | 114 | // Perform text input 115 | std::string line; 116 | while (getline(std::cin, line)) 117 | { 118 | if (line.empty()) 119 | break; 120 | 121 | // Restart the server 122 | if (line == "!") 123 | { 124 | std::cout << "Server restarting..."; 125 | server->Restart(); 126 | std::cout << "Done!" << std::endl; 127 | continue; 128 | } 129 | } 130 | 131 | // Stop the server 132 | std::cout << "Server stopping..."; 133 | server->Stop(); 134 | std::cout << "Done!" << std::endl; 135 | 136 | // Stop the Asio service 137 | std::cout << "Asio service stopping..."; 138 | service->Stop(); 139 | std::cout << "Done!" << std::endl; 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /performance/proto_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 07.01.2022 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/asio/tcp_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include "../proto/simple_protocol.h" 10 | 11 | #include 12 | 13 | #include 14 | 15 | using namespace CppCommon; 16 | using namespace CppServer::Asio; 17 | 18 | class ProtoSession : public TCPSession, public FBE::simple::Sender, public FBE::simple::Receiver 19 | { 20 | public: 21 | using TCPSession::TCPSession; 22 | 23 | protected: 24 | void onError(int error, const std::string& category, const std::string& message) override 25 | { 26 | std::cout << "Protocol session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 27 | } 28 | 29 | protected: 30 | // Protocol handlers 31 | void onReceive(const ::simple::SimpleRequest& request) override 32 | { 33 | // Send response 34 | simple::SimpleResponse response; 35 | response.id = request.id; 36 | response.Hash = 0; 37 | response.Length = (uint32_t)request.Message.size(); 38 | send(response); 39 | } 40 | 41 | // Protocol implementation 42 | void onReceived(const void* buffer, size_t size) override { receive(buffer, size); } 43 | size_t onSend(const void* data, size_t size) override { return SendAsync(data, size) ? size : 0; } 44 | }; 45 | 46 | class ProtoServer : public TCPServer, public FBE::simple::Sender 47 | { 48 | public: 49 | using TCPServer::TCPServer; 50 | 51 | protected: 52 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 53 | { 54 | return std::make_shared(server); 55 | } 56 | 57 | protected: 58 | void onError(int error, const std::string& category, const std::string& message) override 59 | { 60 | std::cout << "Protocol server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 61 | } 62 | 63 | protected: 64 | // Protocol implementation 65 | size_t onSend(const void* data, size_t size) override { Multicast(data, size); return size; } 66 | }; 67 | 68 | int main(int argc, char** argv) 69 | { 70 | auto parser = optparse::OptionParser().version("1.0.0.0"); 71 | 72 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(4444).help("Server port. Default: %default"); 73 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 74 | 75 | optparse::Values options = parser.parse_args(argc, argv); 76 | 77 | // Print help 78 | if (options.get("help")) 79 | { 80 | parser.print_help(); 81 | return 0; 82 | } 83 | 84 | // Server port 85 | int port = options.get("port"); 86 | int threads = options.get("threads"); 87 | 88 | std::cout << "Server port: " << port << std::endl; 89 | std::cout << "Working threads: " << threads << std::endl; 90 | 91 | std::cout << std::endl; 92 | 93 | // Create a new Asio service 94 | auto service = std::make_shared(threads); 95 | 96 | // Start the Asio service 97 | std::cout << "Asio service starting..."; 98 | service->Start(); 99 | std::cout << "Done!" << std::endl; 100 | 101 | // Create a new protocol server 102 | auto server = std::make_shared(service, port); 103 | // server->SetupNoDelay(true); 104 | server->SetupReuseAddress(true); 105 | server->SetupReusePort(true); 106 | 107 | // Start the server 108 | std::cout << "Server starting..."; 109 | server->Start(); 110 | std::cout << "Done!" << std::endl; 111 | 112 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 113 | 114 | // Perform text input 115 | std::string line; 116 | while (getline(std::cin, line)) 117 | { 118 | if (line.empty()) 119 | break; 120 | 121 | // Restart the server 122 | if (line == "!") 123 | { 124 | std::cout << "Server restarting..."; 125 | server->Restart(); 126 | std::cout << "Done!" << std::endl; 127 | continue; 128 | } 129 | } 130 | 131 | // Stop the server 132 | std::cout << "Server stopping..."; 133 | server->Stop(); 134 | std::cout << "Done!" << std::endl; 135 | 136 | // Stop the Asio service 137 | std::cout << "Asio service stopping..."; 138 | service->Stop(); 139 | std::cout << "Done!" << std::endl; 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /performance/ssl_echo_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 16.03.2017 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/asio/ssl_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | 16 | class EchoSession : public SSLSession 17 | { 18 | public: 19 | using SSLSession::SSLSession; 20 | 21 | protected: 22 | void onReceived(const void* buffer, size_t size) override 23 | { 24 | // Resend the message back to the client 25 | SendAsync(buffer, size); 26 | } 27 | 28 | void onError(int error, const std::string& category, const std::string& message) override 29 | { 30 | std::cout << "SSL session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 31 | } 32 | }; 33 | 34 | class EchoServer : public SSLServer 35 | { 36 | public: 37 | using SSLServer::SSLServer; 38 | 39 | protected: 40 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 41 | { 42 | return std::make_shared(server); 43 | } 44 | 45 | protected: 46 | void onError(int error, const std::string& category, const std::string& message) override 47 | { 48 | std::cout << "SSL server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 49 | } 50 | }; 51 | 52 | int main(int argc, char** argv) 53 | { 54 | auto parser = optparse::OptionParser().version("1.0.0.0"); 55 | 56 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(2222).help("Server port. Default: %default"); 57 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 58 | 59 | optparse::Values options = parser.parse_args(argc, argv); 60 | 61 | // Print help 62 | if (options.get("help")) 63 | { 64 | parser.print_help(); 65 | return 0; 66 | } 67 | 68 | // Server port 69 | int port = options.get("port"); 70 | int threads = options.get("threads"); 71 | 72 | std::cout << "Server port: " << port << std::endl; 73 | std::cout << "Working threads: " << threads << std::endl; 74 | 75 | std::cout << std::endl; 76 | 77 | // Create a new Asio service 78 | auto service = std::make_shared(threads); 79 | 80 | // Start the Asio service 81 | std::cout << "Asio service starting..."; 82 | service->Start(); 83 | std::cout << "Done!" << std::endl; 84 | 85 | // Create and prepare a new SSL server context 86 | auto context = std::make_shared(asio::ssl::context::tlsv13); 87 | context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; }); 88 | context->use_certificate_chain_file("../tools/certificates/server.pem"); 89 | context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem); 90 | context->use_tmp_dh_file("../tools/certificates/dh4096.pem"); 91 | 92 | // Create a new echo server 93 | auto server = std::make_shared(service, context, port); 94 | // server->SetupNoDelay(true); 95 | server->SetupReuseAddress(true); 96 | server->SetupReusePort(true); 97 | 98 | // Start the server 99 | std::cout << "Server starting..."; 100 | server->Start(); 101 | std::cout << "Done!" << std::endl; 102 | 103 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 104 | 105 | // Perform text input 106 | std::string line; 107 | while (getline(std::cin, line)) 108 | { 109 | if (line.empty()) 110 | break; 111 | 112 | // Restart the server 113 | if (line == "!") 114 | { 115 | std::cout << "Server restarting..."; 116 | server->Restart(); 117 | std::cout << "Done!" << std::endl; 118 | continue; 119 | } 120 | } 121 | 122 | // Stop the server 123 | std::cout << "Server stopping..."; 124 | server->Stop(); 125 | std::cout << "Done!" << std::endl; 126 | 127 | // Stop the Asio service 128 | std::cout << "Asio service stopping..."; 129 | service->Stop(); 130 | std::cout << "Done!" << std::endl; 131 | 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /performance/tcp_echo_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.03.2017 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/asio/tcp_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | 16 | class EchoSession : public TCPSession 17 | { 18 | public: 19 | using TCPSession::TCPSession; 20 | 21 | protected: 22 | void onReceived(const void* buffer, size_t size) override 23 | { 24 | // Resend the message back to the client 25 | SendAsync(buffer, size); 26 | } 27 | 28 | void onError(int error, const std::string& category, const std::string& message) override 29 | { 30 | std::cout << "TCP session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 31 | } 32 | }; 33 | 34 | class EchoServer : public TCPServer 35 | { 36 | public: 37 | using TCPServer::TCPServer; 38 | 39 | protected: 40 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 41 | { 42 | return std::make_shared(server); 43 | } 44 | 45 | protected: 46 | void onError(int error, const std::string& category, const std::string& message) override 47 | { 48 | std::cout << "TCP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 49 | } 50 | }; 51 | 52 | int main(int argc, char** argv) 53 | { 54 | auto parser = optparse::OptionParser().version("1.0.0.0"); 55 | 56 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(1111).help("Server port. Default: %default"); 57 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 58 | 59 | optparse::Values options = parser.parse_args(argc, argv); 60 | 61 | // Print help 62 | if (options.get("help")) 63 | { 64 | parser.print_help(); 65 | return 0; 66 | } 67 | 68 | // Server port 69 | int port = options.get("port"); 70 | int threads = options.get("threads"); 71 | 72 | std::cout << "Server port: " << port << std::endl; 73 | std::cout << "Working threads: " << threads << std::endl; 74 | 75 | std::cout << std::endl; 76 | 77 | // Create a new Asio service 78 | auto service = std::make_shared(threads); 79 | 80 | // Start the Asio service 81 | std::cout << "Asio service starting..."; 82 | service->Start(); 83 | std::cout << "Done!" << std::endl; 84 | 85 | // Create a new echo server 86 | auto server = std::make_shared(service, port); 87 | // server->SetupNoDelay(true); 88 | server->SetupReuseAddress(true); 89 | server->SetupReusePort(true); 90 | 91 | // Start the server 92 | std::cout << "Server starting..."; 93 | server->Start(); 94 | std::cout << "Done!" << std::endl; 95 | 96 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 97 | 98 | // Perform text input 99 | std::string line; 100 | while (getline(std::cin, line)) 101 | { 102 | if (line.empty()) 103 | break; 104 | 105 | // Restart the server 106 | if (line == "!") 107 | { 108 | std::cout << "Server restarting..."; 109 | server->Restart(); 110 | std::cout << "Done!" << std::endl; 111 | continue; 112 | } 113 | } 114 | 115 | // Stop the server 116 | std::cout << "Server stopping..."; 117 | server->Stop(); 118 | std::cout << "Done!" << std::endl; 119 | 120 | // Stop the Asio service 121 | std::cout << "Asio service stopping..."; 122 | service->Stop(); 123 | std::cout << "Done!" << std::endl; 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /performance/udp_echo_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 15.03.2017 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/asio/udp_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | 16 | class EchoServer : public UDPServer 17 | { 18 | public: 19 | using UDPServer::UDPServer; 20 | 21 | protected: 22 | void onStarted() override 23 | { 24 | // Start receive datagrams 25 | ReceiveAsync(); 26 | } 27 | 28 | void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override 29 | { 30 | // Continue receive datagrams 31 | if (size == 0) 32 | { 33 | ReceiveAsync(); 34 | return; 35 | } 36 | 37 | // Resend the message back to the client 38 | SendAsync(endpoint, buffer, size); 39 | } 40 | 41 | void onSent(const asio::ip::udp::endpoint& endpoint, size_t sent) override 42 | { 43 | // Continue receive datagrams 44 | ReceiveAsync(); 45 | } 46 | 47 | void onError(int error, const std::string& category, const std::string& message) override 48 | { 49 | std::cout << "UDP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 50 | } 51 | }; 52 | 53 | int main(int argc, char** argv) 54 | { 55 | auto parser = optparse::OptionParser().version("1.0.0.0"); 56 | 57 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(3333).help("Server port. Default: %default"); 58 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 59 | 60 | optparse::Values options = parser.parse_args(argc, argv); 61 | 62 | // Print help 63 | if (options.get("help")) 64 | { 65 | parser.print_help(); 66 | return 0; 67 | } 68 | 69 | // Server port 70 | int port = options.get("port"); 71 | int threads = options.get("threads"); 72 | 73 | std::cout << "Server port: " << port << std::endl; 74 | std::cout << "Working threads: " << threads << std::endl; 75 | 76 | std::cout << std::endl; 77 | 78 | // Create a new Asio service 79 | auto service = std::make_shared(threads); 80 | 81 | // Start the Asio service 82 | std::cout << "Asio service starting..."; 83 | service->Start(); 84 | std::cout << "Done!" << std::endl; 85 | 86 | // Create a new echo server 87 | auto server = std::make_shared(service, port); 88 | server->SetupReuseAddress(true); 89 | server->SetupReusePort(true); 90 | 91 | // Start the server 92 | std::cout << "Server starting..."; 93 | server->Start(); 94 | std::cout << "Done!" << std::endl; 95 | 96 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 97 | 98 | // Perform text input 99 | std::string line; 100 | while (getline(std::cin, line)) 101 | { 102 | if (line.empty()) 103 | break; 104 | 105 | // Restart the server 106 | if (line == "!") 107 | { 108 | std::cout << "Server restarting..."; 109 | server->Restart(); 110 | std::cout << "Done!" << std::endl; 111 | continue; 112 | } 113 | } 114 | 115 | // Stop the server 116 | std::cout << "Server stopping..."; 117 | server->Stop(); 118 | std::cout << "Done!" << std::endl; 119 | 120 | // Stop the Asio service 121 | std::cout << "Asio service stopping..."; 122 | service->Stop(); 123 | std::cout << "Done!" << std::endl; 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /performance/udp_multicast_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 29.03.2018 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/asio/udp_server.h" 7 | #include "system/cpu.h" 8 | #include "threads/thread.h" 9 | #include "time/timestamp.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | using namespace CppCommon; 19 | using namespace CppServer::Asio; 20 | 21 | class MulticastServer : public UDPServer 22 | { 23 | public: 24 | using UDPServer::UDPServer; 25 | 26 | protected: 27 | void onError(int error, const std::string& category, const std::string& message) override 28 | { 29 | std::cout << "UDP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 30 | } 31 | }; 32 | 33 | int main(int argc, char** argv) 34 | { 35 | auto parser = optparse::OptionParser().version("1.0.0.0"); 36 | 37 | parser.add_option("-a", "--address").dest("address").set_default("239.255.0.1").help("Server address. Default: %default"); 38 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(3333).help("Server port. Default: %default"); 39 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 40 | parser.add_option("-m", "--messages").dest("messages").action("store").type("int").set_default(1000000).help("Rate of messages per second to send. Default: %default"); 41 | parser.add_option("-s", "--size").dest("size").action("store").type("int").set_default(32).help("Single message size. Default: %default"); 42 | 43 | optparse::Values options = parser.parse_args(argc, argv); 44 | 45 | // Print help 46 | if (options.get("help")) 47 | { 48 | parser.print_help(); 49 | return 0; 50 | } 51 | 52 | // Server port 53 | std::string address(options.get("address")); 54 | int port = options.get("port"); 55 | int threads = options.get("threads"); 56 | int messages_rate = options.get("messages"); 57 | int message_size = options.get("size"); 58 | 59 | std::cout << "Server address: " << address << std::endl; 60 | std::cout << "Server port: " << port << std::endl; 61 | std::cout << "Working threads: " << threads << std::endl; 62 | std::cout << "Messages rate: " << messages_rate << std::endl; 63 | std::cout << "Message size: " << message_size << std::endl; 64 | 65 | std::cout << std::endl; 66 | 67 | // Create a new Asio service 68 | auto service = std::make_shared(threads); 69 | 70 | // Start the Asio service 71 | std::cout << "Asio service starting..."; 72 | service->Start(); 73 | std::cout << "Done!" << std::endl; 74 | 75 | // Create a new multicast server 76 | auto server = std::make_shared(service, 0); 77 | server->SetupReuseAddress(true); 78 | server->SetupReusePort(true); 79 | 80 | // Start the server 81 | std::cout << "Server starting..."; 82 | server->Start(address, port); 83 | std::cout << "Done!" << std::endl; 84 | 85 | // Start the multicasting thread 86 | std::atomic multicasting(true); 87 | auto multicaster = std::thread([&server, &multicasting, messages_rate, message_size]() 88 | { 89 | // Prepare message to multicast 90 | std::vector message_to_send(message_size); 91 | 92 | // Multicasting loop 93 | while (multicasting) 94 | { 95 | auto start = UtcTimestamp(); 96 | for (int i = 0; i < messages_rate; ++i) 97 | server->Multicast(message_to_send.data(), message_to_send.size()); 98 | auto end = UtcTimestamp(); 99 | 100 | // Sleep for remaining time or yield 101 | auto milliseconds = (end - start).milliseconds(); 102 | if (milliseconds < 1000) 103 | Thread::Sleep(1000 - milliseconds); 104 | else 105 | Thread::Yield(); 106 | } 107 | }); 108 | 109 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 110 | 111 | // Perform text input 112 | std::string line; 113 | while (getline(std::cin, line)) 114 | { 115 | if (line.empty()) 116 | break; 117 | 118 | // Restart the server 119 | if (line == "!") 120 | { 121 | std::cout << "Server restarting..."; 122 | server->Restart(); 123 | std::cout << "Done!" << std::endl; 124 | continue; 125 | } 126 | } 127 | 128 | // Stop the multicasting thread 129 | multicasting = false; 130 | multicaster.join(); 131 | 132 | // Stop the server 133 | std::cout << "Server stopping..."; 134 | server->Stop(); 135 | std::cout << "Done!" << std::endl; 136 | 137 | // Stop the Asio service 138 | std::cout << "Asio service stopping..."; 139 | service->Stop(); 140 | std::cout << "Done!" << std::endl; 141 | 142 | return 0; 143 | } 144 | -------------------------------------------------------------------------------- /performance/ws_echo_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 28.05.2019 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/ws/ws_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | using namespace CppServer::WS; 16 | 17 | class EchoSession : public WSSession 18 | { 19 | public: 20 | using WSSession::WSSession; 21 | 22 | protected: 23 | void onWSReceived(const void* buffer, size_t size) override 24 | { 25 | // Resend the message back to the client 26 | SendBinaryAsync(buffer, size); 27 | } 28 | 29 | void onError(int error, const std::string& category, const std::string& message) override 30 | { 31 | std::cout << "WebSocket session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 32 | } 33 | }; 34 | 35 | class EchoServer : public WSServer 36 | { 37 | public: 38 | using WSServer::WSServer; 39 | 40 | protected: 41 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 42 | { 43 | return std::make_shared(std::dynamic_pointer_cast(server)); 44 | } 45 | 46 | protected: 47 | void onError(int error, const std::string& category, const std::string& message) override 48 | { 49 | std::cout << "WebSocket server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 50 | } 51 | }; 52 | 53 | int main(int argc, char** argv) 54 | { 55 | auto parser = optparse::OptionParser().version("1.0.0.0"); 56 | 57 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(8080).help("Server port. Default: %default"); 58 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 59 | 60 | optparse::Values options = parser.parse_args(argc, argv); 61 | 62 | // Print help 63 | if (options.get("help")) 64 | { 65 | parser.print_help(); 66 | return 0; 67 | } 68 | 69 | // Server port 70 | int port = options.get("port"); 71 | int threads = options.get("threads"); 72 | 73 | std::cout << "Server port: " << port << std::endl; 74 | std::cout << "Working threads: " << threads << std::endl; 75 | 76 | std::cout << std::endl; 77 | 78 | // Create a new Asio service 79 | auto service = std::make_shared(threads); 80 | 81 | // Start the Asio service 82 | std::cout << "Asio service starting..."; 83 | service->Start(); 84 | std::cout << "Done!" << std::endl; 85 | 86 | // Create a new echo server 87 | auto server = std::make_shared(service, port); 88 | // server->SetupNoDelay(true); 89 | server->SetupReuseAddress(true); 90 | server->SetupReusePort(true); 91 | 92 | // Start the server 93 | std::cout << "Server starting..."; 94 | server->Start(); 95 | std::cout << "Done!" << std::endl; 96 | 97 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 98 | 99 | // Perform text input 100 | std::string line; 101 | while (getline(std::cin, line)) 102 | { 103 | if (line.empty()) 104 | break; 105 | 106 | // Restart the server 107 | if (line == "!") 108 | { 109 | std::cout << "Server restarting..."; 110 | server->Restart(); 111 | std::cout << "Done!" << std::endl; 112 | continue; 113 | } 114 | } 115 | 116 | // Stop the server 117 | std::cout << "Server stopping..."; 118 | server->Stop(); 119 | std::cout << "Done!" << std::endl; 120 | 121 | // Stop the Asio service 122 | std::cout << "Asio service stopping..."; 123 | service->Stop(); 124 | std::cout << "Done!" << std::endl; 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /performance/wss_echo_server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 28.05.2019 3 | // 4 | 5 | #include "server/asio/service.h" 6 | #include "server/ws/wss_server.h" 7 | #include "system/cpu.h" 8 | 9 | #include 10 | 11 | #include 12 | 13 | using namespace CppCommon; 14 | using namespace CppServer::Asio; 15 | using namespace CppServer::WS; 16 | 17 | class EchoSession : public WSSSession 18 | { 19 | public: 20 | using WSSSession::WSSSession; 21 | 22 | protected: 23 | void onWSReceived(const void* buffer, size_t size) override 24 | { 25 | // Resend the message back to the client 26 | SendBinaryAsync(buffer, size); 27 | } 28 | 29 | void onError(int error, const std::string& category, const std::string& message) override 30 | { 31 | std::cout << "WebSocket secure session caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 32 | } 33 | }; 34 | 35 | class EchoServer : public WSSServer 36 | { 37 | public: 38 | using WSSServer::WSSServer; 39 | 40 | protected: 41 | std::shared_ptr CreateSession(const std::shared_ptr& server) override 42 | { 43 | return std::make_shared(std::dynamic_pointer_cast(server)); 44 | } 45 | 46 | protected: 47 | void onError(int error, const std::string& category, const std::string& message) override 48 | { 49 | std::cout << "WebSocket secure server caught an error with code " << error << " and category '" << category << "': " << message << std::endl; 50 | } 51 | }; 52 | 53 | int main(int argc, char** argv) 54 | { 55 | auto parser = optparse::OptionParser().version("1.0.0.0"); 56 | 57 | parser.add_option("-p", "--port").dest("port").action("store").type("int").set_default(8443).help("Server port. Default: %default"); 58 | parser.add_option("-t", "--threads").dest("threads").action("store").type("int").set_default(CPU::PhysicalCores()).help("Count of working threads. Default: %default"); 59 | 60 | optparse::Values options = parser.parse_args(argc, argv); 61 | 62 | // Print help 63 | if (options.get("help")) 64 | { 65 | parser.print_help(); 66 | return 0; 67 | } 68 | 69 | // Server port 70 | int port = options.get("port"); 71 | int threads = options.get("threads"); 72 | 73 | std::cout << "Server port: " << port << std::endl; 74 | std::cout << "Working threads: " << threads << std::endl; 75 | 76 | std::cout << std::endl; 77 | 78 | // Create a new Asio service 79 | auto service = std::make_shared(threads); 80 | 81 | // Start the Asio service 82 | std::cout << "Asio service starting..."; 83 | service->Start(); 84 | std::cout << "Done!" << std::endl; 85 | 86 | // Create and prepare a new SSL server context 87 | auto context = std::make_shared(asio::ssl::context::tlsv13); 88 | context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; }); 89 | context->use_certificate_chain_file("../tools/certificates/server.pem"); 90 | context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem); 91 | context->use_tmp_dh_file("../tools/certificates/dh4096.pem"); 92 | 93 | // Create a new echo server 94 | auto server = std::make_shared(service, context, port); 95 | // server->SetupNoDelay(true); 96 | server->SetupReuseAddress(true); 97 | server->SetupReusePort(true); 98 | 99 | // Start the server 100 | std::cout << "Server starting..."; 101 | server->Start(); 102 | std::cout << "Done!" << std::endl; 103 | 104 | std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl; 105 | 106 | // Perform text input 107 | std::string line; 108 | while (getline(std::cin, line)) 109 | { 110 | if (line.empty()) 111 | break; 112 | 113 | // Restart the server 114 | if (line == "!") 115 | { 116 | std::cout << "Server restarting..."; 117 | server->Restart(); 118 | std::cout << "Done!" << std::endl; 119 | continue; 120 | } 121 | } 122 | 123 | // Stop the server 124 | std::cout << "Server stopping..."; 125 | server->Stop(); 126 | std::cout << "Done!" << std::endl; 127 | 128 | // Stop the Asio service 129 | std::cout << "Asio service stopping..."; 130 | service->Stop(); 131 | std::cout << "Done!" << std::endl; 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /proto/fbe_protocol.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // Automatically generated by the Fast Binary Encoding compiler, do not modify! 3 | // https://github.com/chronoxor/FastBinaryEncoding 4 | // Source: FBE 5 | // FBE version: 1.15.0.0 6 | //------------------------------------------------------------------------------ 7 | 8 | #pragma once 9 | 10 | #if defined(__clang__) 11 | #pragma clang system_header 12 | #elif defined(__GNUC__) 13 | #pragma GCC system_header 14 | #elif defined(_MSC_VER) 15 | #pragma system_header 16 | #endif 17 | 18 | #include "fbe.h" 19 | 20 | namespace FBE { 21 | 22 | // Fast Binary Encoding base sender 23 | class Sender 24 | { 25 | public: 26 | Sender(const Sender&) = delete; 27 | Sender(Sender&&) noexcept = delete; 28 | virtual ~Sender() = default; 29 | 30 | Sender& operator=(const Sender&) = delete; 31 | Sender& operator=(Sender&&) noexcept = delete; 32 | 33 | // Get the sender buffer 34 | FBEBuffer& buffer() noexcept { return *_buffer; } 35 | const FBEBuffer& buffer() const noexcept { return *_buffer; } 36 | 37 | // Get the final protocol flag 38 | bool final() const noexcept { return _final; } 39 | 40 | // Get the logging flag 41 | bool logging() const noexcept { return _logging; } 42 | // Enable/Disable logging 43 | void logging(bool enable) noexcept { _logging = enable; } 44 | 45 | // Reset the sender buffer 46 | void reset() noexcept { _buffer->reset(); } 47 | 48 | // Send serialized buffer. 49 | // Direct call of the method requires knowledge about internals of FBE models serialization. 50 | // Use it with care! 51 | size_t send_serialized(size_t serialized); 52 | 53 | protected: 54 | // Send message handler 55 | virtual size_t onSend(const void* data, size_t size) = 0; 56 | // Send log message handler 57 | virtual void onSendLog(const std::string& message) const {} 58 | 59 | protected: 60 | std::shared_ptr _buffer; 61 | bool _logging; 62 | bool _final; 63 | 64 | Sender() : Sender(nullptr) {} 65 | Sender(const std::shared_ptr& buffer) : _logging(false), _final(false) { _buffer = buffer ? buffer : std::make_shared(); } 66 | 67 | // Enable/Disable final protocol 68 | void final(bool enable) noexcept { _final = enable; } 69 | }; 70 | 71 | // Fast Binary Encoding base receiver 72 | class Receiver 73 | { 74 | public: 75 | Receiver(const Receiver&) = delete; 76 | Receiver(Receiver&&) = delete; 77 | virtual ~Receiver() = default; 78 | 79 | Receiver& operator=(const Receiver&) = delete; 80 | Receiver& operator=(Receiver&&) = delete; 81 | 82 | // Get the receiver buffer 83 | FBEBuffer& buffer() noexcept { return *_buffer; } 84 | const FBEBuffer& buffer() const noexcept { return *_buffer; } 85 | 86 | // Get the final protocol flag 87 | bool final() const noexcept { return _final; } 88 | 89 | // Get the logging flag 90 | bool logging() const noexcept { return _logging; } 91 | // Enable/Disable logging 92 | void logging(bool enable) noexcept { _logging = enable; } 93 | 94 | // Reset the receiver buffer 95 | void reset() noexcept { _buffer->reset(); } 96 | 97 | // Receive data 98 | void receive(const void* data, size_t size); 99 | 100 | protected: 101 | // Receive message handler 102 | virtual bool onReceive(size_t type, const void* data, size_t size) = 0; 103 | // Receive log message handler 104 | virtual void onReceiveLog(const std::string& message) const {} 105 | 106 | protected: 107 | std::shared_ptr _buffer; 108 | bool _logging; 109 | bool _final; 110 | 111 | Receiver() : Receiver(nullptr) {} 112 | Receiver(const std::shared_ptr& buffer) : _logging(false), _final(false) { _buffer = buffer ? buffer : std::make_shared(); } 113 | 114 | // Enable/Disable final protocol 115 | void final(bool enable) noexcept { _final = enable; } 116 | }; 117 | 118 | } // namespace FBE 119 | -------------------------------------------------------------------------------- /proto/simple.fbe: -------------------------------------------------------------------------------- 1 | /* 2 | Simple Fast Binary Encoding protocol for CppServer 3 | https://github.com/chronoxor/FastBinaryEncoding 4 | 5 | Generate protocol command: fbec --cpp --proto --input=simple.fbe --output=. 6 | */ 7 | 8 | // Domain declaration 9 | domain com.chronoxor 10 | 11 | // Package declaration 12 | package simple 13 | 14 | // Protocol version 15 | version 1.0 16 | 17 | // Simple request message 18 | [request] 19 | [response(SimpleResponse)] 20 | [reject(SimpleReject)] 21 | message SimpleRequest 22 | { 23 | // Request Id 24 | uuid [id] = uuid1; 25 | // Request message 26 | string Message; 27 | } 28 | 29 | // Simple response 30 | message SimpleResponse 31 | { 32 | // Response Id 33 | uuid [id] = uuid1; 34 | // Calculated message length 35 | uint32 Length; 36 | // Calculated message hash 37 | uint32 Hash; 38 | } 39 | 40 | // Simple reject 41 | message SimpleReject 42 | { 43 | // Reject Id 44 | uuid [id] = uuid1; 45 | // Error message 46 | string Error; 47 | } 48 | 49 | // Simple notification 50 | message SimpleNotify 51 | { 52 | // Server notification 53 | string Notification; 54 | } 55 | 56 | // Disconnect request message 57 | [request] 58 | message DisconnectRequest 59 | { 60 | // Request Id 61 | uuid [id] = uuid1; 62 | } 63 | -------------------------------------------------------------------------------- /source/server/asio/ssl_context.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ssl_context.cpp 3 | \brief SSL context implementation 4 | \author Ivan Shynkarenka 5 | \date 12.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/asio/ssl_context.h" 10 | 11 | #if defined(_WIN32) || defined(_WIN64) 12 | #include 13 | #endif 14 | 15 | namespace CppServer { 16 | namespace Asio { 17 | 18 | void SSLContext::set_root_certs() 19 | { 20 | #if defined(_WIN32) || defined(_WIN64) 21 | HCERTSTORE hStore = CertOpenSystemStore(0, "ROOT"); 22 | if (hStore == nullptr) 23 | return; 24 | 25 | X509_STORE* store = X509_STORE_new(); 26 | PCCERT_CONTEXT pContext = nullptr; 27 | while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != nullptr) 28 | { 29 | // Convert from DER to internal format 30 | X509* x509 = d2i_X509(nullptr, (const unsigned char**)&pContext->pbCertEncoded, pContext->cbCertEncoded); 31 | if (x509 != nullptr) 32 | { 33 | X509_STORE_add_cert(store, x509); 34 | X509_free(x509); 35 | } 36 | } 37 | 38 | CertFreeCertificateContext(pContext); 39 | CertCloseStore(hStore, 0); 40 | 41 | // Attach X509_STORE to the current SSL context 42 | SSL_CTX_set_cert_store(native_handle(), store); 43 | #endif 44 | } 45 | 46 | } // namespace Asio 47 | } // namespace CppServer 48 | -------------------------------------------------------------------------------- /source/server/asio/tcp_resolver.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file tcp_resolver.cpp 3 | \brief TCP resolver implementation 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/asio/tcp_resolver.h" 10 | 11 | namespace CppServer { 12 | namespace Asio { 13 | 14 | TCPResolver::TCPResolver(const std::shared_ptr& service) 15 | : _service(service), 16 | _io_service(_service->GetAsioService()), 17 | _strand(*_io_service), 18 | _strand_required(_service->IsStrandRequired()), 19 | _resolver(*_io_service) 20 | { 21 | assert((service != nullptr) && "Asio service is invalid!"); 22 | if (service == nullptr) 23 | throw CppCommon::ArgumentException("Asio service is invalid!"); 24 | } 25 | 26 | } // namespace Asio 27 | } // namespace CppServer 28 | -------------------------------------------------------------------------------- /source/server/asio/udp_resolver.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file udp_resolver.cpp 3 | \brief UDP resolver implementation 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/asio/udp_resolver.h" 10 | 11 | namespace CppServer { 12 | namespace Asio { 13 | 14 | UDPResolver::UDPResolver(const std::shared_ptr& service) 15 | : _service(service), 16 | _io_service(_service->GetAsioService()), 17 | _strand(*_io_service), 18 | _strand_required(_service->IsStrandRequired()), 19 | _resolver(*_io_service) 20 | { 21 | assert((service != nullptr) && "Asio service is invalid!"); 22 | if (service == nullptr) 23 | throw CppCommon::ArgumentException("Asio service is invalid!"); 24 | } 25 | 26 | } // namespace Asio 27 | } // namespace CppServer 28 | -------------------------------------------------------------------------------- /source/server/http/http_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_client.cpp 3 | \brief HTTP client implementation 4 | \author Ivan Shynkarenka 5 | \date 08.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/http/http_client.h" 10 | 11 | namespace CppServer { 12 | namespace HTTP { 13 | 14 | void HTTPClient::onReceived(const void* buffer, size_t size) 15 | { 16 | // Receive HTTP response header 17 | if (_response.IsPendingHeader()) 18 | { 19 | if (_response.ReceiveHeader(buffer, size)) 20 | onReceivedResponseHeader(_response); 21 | 22 | size = 0; 23 | } 24 | 25 | // Check for HTTP response error 26 | if (_response.error()) 27 | { 28 | onReceivedResponseError(_response, "Invalid HTTP response!"); 29 | _response.Clear(); 30 | DisconnectAsync(); 31 | return; 32 | } 33 | 34 | // Receive HTTP response body 35 | if (_response.ReceiveBody(buffer, size)) 36 | { 37 | onReceivedResponse(_response); 38 | _response.Clear(); 39 | return; 40 | } 41 | 42 | // Check for HTTP response error 43 | if (_response.error()) 44 | { 45 | onReceivedResponseError(_response, "Invalid HTTP response!"); 46 | _response.Clear(); 47 | DisconnectAsync(); 48 | return; 49 | } 50 | } 51 | 52 | void HTTPClient::onDisconnected() 53 | { 54 | // Receive HTTP response body 55 | if (_response.IsPendingBody()) 56 | { 57 | onReceivedResponse(_response); 58 | _response.Clear(); 59 | return; 60 | } 61 | } 62 | 63 | std::future HTTPClientEx::SendRequest(const HTTPRequest& request, const CppCommon::Timespan& timeout) 64 | { 65 | // Create TCP resolver if the current one is empty 66 | if (!_resolver) 67 | _resolver = std::make_shared(service()); 68 | // Create timeout check timer if the current one is empty 69 | if (!_timeout) 70 | _timeout = std::make_shared(service()); 71 | 72 | _promise = std::promise(); 73 | _request = request; 74 | 75 | // Check if the HTTP request is valid 76 | if (_request.empty() || _request.error()) 77 | { 78 | SetPromiseError("Invalid HTTP request!"); 79 | return _promise.get_future(); 80 | } 81 | 82 | if (!IsConnected()) 83 | { 84 | // Connect to the Web server 85 | if (!ConnectAsync(_resolver)) 86 | { 87 | SetPromiseError("Connection failed!"); 88 | return _promise.get_future(); 89 | } 90 | } 91 | else 92 | { 93 | // Send prepared HTTP request 94 | if (!SendRequestAsync()) 95 | { 96 | SetPromiseError("Failed to send HTTP request!"); 97 | return _promise.get_future(); 98 | } 99 | } 100 | 101 | // Setup timeout check timer 102 | auto self(this->shared_from_this()); 103 | auto timeout_handler = [this, self](bool canceled) 104 | { 105 | if (canceled) 106 | return; 107 | 108 | // Disconnect on timeout 109 | onReceivedResponseError(_response, "Timeout!"); 110 | _response.Clear(); 111 | DisconnectAsync(); 112 | }; 113 | if (!_timeout->Setup(timeout_handler, timeout) || !_timeout->WaitAsync()) 114 | { 115 | SetPromiseError("Failed to setup timeout timer!"); 116 | return _promise.get_future(); 117 | } 118 | 119 | return _promise.get_future(); 120 | } 121 | 122 | void HTTPClientEx::onConnected() 123 | { 124 | HTTPClient::onConnected(); 125 | 126 | // Send prepared HTTP request on connect 127 | if (!_request.empty() && !_request.error()) 128 | if (!SendRequestAsync()) 129 | SetPromiseError("Failed to send HTTP request!"); 130 | } 131 | 132 | void HTTPClientEx::onDisconnected() 133 | { 134 | // Cancel timeout check timer 135 | if (_timeout) 136 | _timeout->Cancel(); 137 | 138 | HTTPClient::onDisconnected(); 139 | } 140 | 141 | void HTTPClientEx::onReceivedResponse(const HTTPResponse& response) 142 | { 143 | // Cancel timeout check timer 144 | if (_timeout) 145 | _timeout->Cancel(); 146 | 147 | SetPromiseValue(response); 148 | } 149 | 150 | void HTTPClientEx::onReceivedResponseError(const HTTPResponse& response, const std::string& error) 151 | { 152 | // Cancel timeout check timer 153 | if (_timeout) 154 | _timeout->Cancel(); 155 | 156 | SetPromiseError(error); 157 | } 158 | 159 | void HTTPClientEx::SetPromiseValue(const HTTPResponse& response) 160 | { 161 | _promise.set_value(response); 162 | _request.Clear(); 163 | } 164 | 165 | void HTTPClientEx::SetPromiseError(const std::string& error) 166 | { 167 | _promise.set_exception(std::make_exception_ptr(std::runtime_error(error))); 168 | _request.Clear(); 169 | } 170 | 171 | } // namespace HTTP 172 | } // namespace CppServer 173 | -------------------------------------------------------------------------------- /source/server/http/http_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_server.cpp 3 | \brief HTTP server implementation 4 | \author Ivan Shynkarenka 5 | \date 30.04.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/http/http_server.h" 10 | 11 | #include "string/format.h" 12 | 13 | namespace CppServer { 14 | namespace HTTP { 15 | 16 | void HTTPServer::AddStaticContent(const CppCommon::Path& path, const std::string& prefix, const CppCommon::Timespan& timeout) 17 | { 18 | auto hanlder = [](CppCommon::FileCache & cache, const std::string& key, const std::string& value, const CppCommon::Timespan& timespan) 19 | { 20 | auto response = HTTPResponse(); 21 | response.SetBegin(200); 22 | response.SetContentType(CppCommon::Path(key).extension().string()); 23 | response.SetHeader("Cache-Control", CppCommon::format("max-age={}", timespan.seconds())); 24 | response.SetBody(value); 25 | return cache.insert(key, response.cache(), timespan); 26 | }; 27 | 28 | cache().insert_path(path, prefix, timeout, hanlder); 29 | } 30 | 31 | } // namespace HTTP 32 | } // namespace CppServer 33 | -------------------------------------------------------------------------------- /source/server/http/http_session.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file http_session.cpp 3 | \brief HTTP session implementation 4 | \author Ivan Shynkarenka 5 | \date 30.04.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/http/http_session.h" 10 | #include "server/http/http_server.h" 11 | 12 | namespace CppServer { 13 | namespace HTTP { 14 | 15 | HTTPSession::HTTPSession(const std::shared_ptr& server) 16 | : Asio::TCPSession(server), 17 | _cache(server->cache()) 18 | { 19 | } 20 | 21 | void HTTPSession::onReceived(const void* buffer, size_t size) 22 | { 23 | // Receive HTTP request header 24 | if (_request.IsPendingHeader()) 25 | { 26 | if (_request.ReceiveHeader(buffer, size)) 27 | onReceivedRequestHeader(_request); 28 | 29 | size = 0; 30 | } 31 | 32 | // Check for HTTP request error 33 | if (_request.error()) 34 | { 35 | onReceivedRequestError(_request, "Invalid HTTP request!"); 36 | _request.Clear(); 37 | Disconnect(); 38 | return; 39 | } 40 | 41 | // Receive HTTP request body 42 | if (_request.ReceiveBody(buffer, size)) 43 | { 44 | onReceivedRequestInternal(_request); 45 | _request.Clear(); 46 | return; 47 | } 48 | 49 | // Check for HTTP request error 50 | if (_request.error()) 51 | { 52 | onReceivedRequestError(_request, "Invalid HTTP request!"); 53 | _request.Clear(); 54 | Disconnect(); 55 | return; 56 | } 57 | } 58 | 59 | void HTTPSession::onDisconnected() 60 | { 61 | // Receive HTTP request body 62 | if (_request.IsPendingBody()) 63 | { 64 | onReceivedRequestInternal(_request); 65 | _request.Clear(); 66 | return; 67 | } 68 | } 69 | 70 | void HTTPSession::onReceivedRequestInternal(const HTTPRequest& request) 71 | { 72 | // Try to get the cached response 73 | if (request.method() == "GET") 74 | { 75 | std::string_view url = request.url(); 76 | size_t index = url.find('?'); 77 | auto response = cache().find(std::string((index == std::string_view::npos) ? url : url.substr(0, index))); 78 | if (response.first) 79 | { 80 | // Process the request with the cached response 81 | onReceivedCachedRequest(request, response.second); 82 | return; 83 | } 84 | } 85 | 86 | // Process the request 87 | onReceivedRequest(request); 88 | } 89 | 90 | } // namespace HTTP 91 | } // namespace CppServer 92 | -------------------------------------------------------------------------------- /source/server/http/https_client.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file https_client.cpp 3 | \brief HTTPS client implementation 4 | \author Ivan Shynkarenka 5 | \date 12.02.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/http/https_client.h" 10 | 11 | namespace CppServer { 12 | namespace HTTP { 13 | 14 | void HTTPSClient::onReceived(const void* buffer, size_t size) 15 | { 16 | // Receive HTTP response header 17 | if (_response.IsPendingHeader()) 18 | { 19 | if (_response.ReceiveHeader(buffer, size)) 20 | onReceivedResponseHeader(_response); 21 | 22 | size = 0; 23 | } 24 | 25 | // Check for HTTP response error 26 | if (_response.error()) 27 | { 28 | onReceivedResponseError(_response, "Invalid HTTP response!"); 29 | _response.Clear(); 30 | DisconnectAsync(); 31 | return; 32 | } 33 | 34 | // Receive HTTP response body 35 | if (_response.ReceiveBody(buffer, size)) 36 | { 37 | onReceivedResponse(_response); 38 | _response.Clear(); 39 | return; 40 | } 41 | 42 | // Check for HTTP response error 43 | if (_response.error()) 44 | { 45 | onReceivedResponseError(_response, "Invalid HTTP response!"); 46 | _response.Clear(); 47 | DisconnectAsync(); 48 | return; 49 | } 50 | } 51 | 52 | void HTTPSClient::onDisconnected() 53 | { 54 | // Receive HTTP response body 55 | if (_response.IsPendingBody()) 56 | { 57 | onReceivedResponse(_response); 58 | _response.Clear(); 59 | return; 60 | } 61 | } 62 | 63 | std::future HTTPSClientEx::SendRequest(const HTTPRequest& request, const CppCommon::Timespan& timeout) 64 | { 65 | // Create TCP resolver if the current one is empty 66 | if (!_resolver) 67 | _resolver = std::make_shared(service()); 68 | // Create timeout check timer if the current one is empty 69 | if (!_timeout) 70 | _timeout = std::make_shared(service()); 71 | 72 | _promise = std::promise(); 73 | _request = request; 74 | 75 | // Check if the HTTP request is valid 76 | if (_request.empty() || _request.error()) 77 | { 78 | SetPromiseError("Invalid HTTP request!"); 79 | return _promise.get_future(); 80 | } 81 | 82 | if (!IsHandshaked()) 83 | { 84 | // Connect to the Web server 85 | if (!ConnectAsync(_resolver)) 86 | { 87 | SetPromiseError("Connection failed!"); 88 | return _promise.get_future(); 89 | } 90 | } 91 | else 92 | { 93 | // Send prepared HTTP request 94 | if (!SendRequestAsync()) 95 | { 96 | SetPromiseError("Failed to send HTTP request!"); 97 | return _promise.get_future(); 98 | } 99 | } 100 | 101 | // Setup timeout check timer 102 | auto self(this->shared_from_this()); 103 | auto timeout_handler = [this, self](bool canceled) 104 | { 105 | if (canceled) 106 | return; 107 | 108 | // Disconnect on timeout 109 | onReceivedResponseError(_response, "Timeout!"); 110 | _response.Clear(); 111 | DisconnectAsync(); 112 | }; 113 | if (!_timeout->Setup(timeout_handler, timeout) || !_timeout->WaitAsync()) 114 | { 115 | SetPromiseError("Failed to setup timeout timer!"); 116 | return _promise.get_future(); 117 | } 118 | 119 | return _promise.get_future(); 120 | } 121 | 122 | void HTTPSClientEx::onHandshaked() 123 | { 124 | HTTPSClient::onHandshaked(); 125 | 126 | // Send prepared HTTP request on connect 127 | if (!_request.empty() && !_request.error()) 128 | if (!SendRequestAsync()) 129 | SetPromiseError("Failed to send HTTP request!"); 130 | } 131 | 132 | void HTTPSClientEx::onDisconnected() 133 | { 134 | // Cancel timeout check timer 135 | if (_timeout) 136 | _timeout->Cancel(); 137 | 138 | HTTPSClient::onDisconnected(); 139 | } 140 | 141 | void HTTPSClientEx::onReceivedResponse(const HTTPResponse& response) 142 | { 143 | // Cancel timeout check timer 144 | if (_timeout) 145 | _timeout->Cancel(); 146 | 147 | SetPromiseValue(response); 148 | } 149 | 150 | void HTTPSClientEx::onReceivedResponseError(const HTTPResponse& response, const std::string& error) 151 | { 152 | // Cancel timeout check timer 153 | if (_timeout) 154 | _timeout->Cancel(); 155 | 156 | SetPromiseError(error); 157 | } 158 | 159 | void HTTPSClientEx::SetPromiseValue(const HTTPResponse& response) 160 | { 161 | _promise.set_value(response); 162 | _request.Clear(); 163 | } 164 | 165 | void HTTPSClientEx::SetPromiseError(const std::string& error) 166 | { 167 | _promise.set_exception(std::make_exception_ptr(std::runtime_error(error))); 168 | _request.Clear(); 169 | } 170 | 171 | } // namespace HTTP 172 | } // namespace CppServer 173 | -------------------------------------------------------------------------------- /source/server/http/https_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file https_server.cpp 3 | \brief HTTPS server implementation 4 | \author Ivan Shynkarenka 5 | \date 30.04.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/http/https_server.h" 10 | 11 | #include "string/format.h" 12 | 13 | namespace CppServer { 14 | namespace HTTP { 15 | 16 | void HTTPSServer::AddStaticContent(const CppCommon::Path& path, const std::string& prefix, const CppCommon::Timespan& timeout) 17 | { 18 | auto hanlder = [](CppCommon::FileCache & cache, const std::string& key, const std::string& value, const CppCommon::Timespan& timespan) 19 | { 20 | auto response = HTTPResponse(); 21 | response.SetBegin(200); 22 | response.SetContentType(CppCommon::Path(key).extension().string()); 23 | response.SetHeader("Cache-Control", CppCommon::format("max-age={}", timespan.seconds())); 24 | response.SetBody(value); 25 | return cache.insert(key, response.cache(), timespan); 26 | }; 27 | 28 | cache().insert_path(path, prefix, timeout, hanlder); 29 | } 30 | 31 | } // namespace HTTP 32 | } // namespace CppServer 33 | -------------------------------------------------------------------------------- /source/server/http/https_session.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file https_session.cpp 3 | \brief HTTPS session implementation 4 | \author Ivan Shynkarenka 5 | \date 30.04.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/http/https_session.h" 10 | #include "server/http/https_server.h" 11 | 12 | namespace CppServer { 13 | namespace HTTP { 14 | 15 | HTTPSSession::HTTPSSession(const std::shared_ptr& server) 16 | : Asio::SSLSession(server), 17 | _cache(server->cache()) 18 | { 19 | } 20 | 21 | void HTTPSSession::onReceived(const void* buffer, size_t size) 22 | { 23 | // Receive HTTP request header 24 | if (_request.IsPendingHeader()) 25 | { 26 | if (_request.ReceiveHeader(buffer, size)) 27 | onReceivedRequestHeader(_request); 28 | 29 | size = 0; 30 | } 31 | 32 | // Check for HTTP request error 33 | if (_request.error()) 34 | { 35 | onReceivedRequestError(_request, "Invalid HTTP request!"); 36 | _request.Clear(); 37 | Disconnect(); 38 | return; 39 | } 40 | 41 | // Receive HTTP request body 42 | if (_request.ReceiveBody(buffer, size)) 43 | { 44 | onReceivedRequestInternal(_request); 45 | _request.Clear(); 46 | return; 47 | } 48 | 49 | // Check for HTTP request error 50 | if (_request.error()) 51 | { 52 | onReceivedRequestError(_request, "Invalid HTTP request!"); 53 | _request.Clear(); 54 | Disconnect(); 55 | return; 56 | } 57 | } 58 | 59 | void HTTPSSession::onDisconnected() 60 | { 61 | // Receive HTTP request body 62 | if (_request.IsPendingBody()) 63 | { 64 | onReceivedRequestInternal(_request); 65 | _request.Clear(); 66 | return; 67 | } 68 | } 69 | 70 | void HTTPSSession::onReceivedRequestInternal(const HTTPRequest& request) 71 | { 72 | // Try to get the cached response 73 | if (request.method() == "GET") 74 | { 75 | std::string_view url = request.url(); 76 | size_t index = url.find('?'); 77 | auto response = cache().find(std::string((index == std::string_view::npos) ? url : url.substr(0, index))); 78 | if (response.first) 79 | { 80 | // Process the request with the cached response 81 | onReceivedCachedRequest(request, response.second); 82 | return; 83 | } 84 | } 85 | 86 | // Process the request 87 | onReceivedRequest(request); 88 | } 89 | 90 | } // namespace HTTP 91 | } // namespace CppServer 92 | -------------------------------------------------------------------------------- /source/server/ws/ws_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file ws_server.cpp 3 | \brief WebSocket server implementation 4 | \author Ivan Shynkarenka 5 | \date 27.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/ws/ws_server.h" 10 | 11 | namespace CppServer { 12 | namespace WS { 13 | 14 | bool WSServer::CloseAll(int status, const void* buffer, size_t size) 15 | { 16 | std::scoped_lock locker(_ws_send_lock); 17 | 18 | PrepareSendFrame(WS_FIN | WS_CLOSE, false, buffer, size, status); 19 | if (!Multicast(_ws_send_buffer.data(), _ws_send_buffer.size())) 20 | return false; 21 | 22 | return HTTPServer::DisconnectAll(); 23 | } 24 | 25 | bool WSServer::CloseAll(int status, std::string_view text) 26 | { 27 | std::scoped_lock locker(_ws_send_lock); 28 | 29 | PrepareSendFrame(WS_FIN | WS_CLOSE, false, text.data(), text.size(), status); 30 | if (!Multicast(_ws_send_buffer.data(), _ws_send_buffer.size())) 31 | return false; 32 | 33 | return HTTPServer::DisconnectAll(); 34 | } 35 | 36 | bool WSServer::Multicast(const void* buffer, size_t size) 37 | { 38 | if (!IsStarted()) 39 | return false; 40 | 41 | if (size == 0) 42 | return true; 43 | 44 | assert((buffer != nullptr) && "Pointer to the buffer should not be null!"); 45 | if (buffer == nullptr) 46 | return false; 47 | 48 | std::shared_lock locker(_sessions_lock); 49 | 50 | // Multicast all WebSocket sessions 51 | for (auto& session : _sessions) 52 | { 53 | auto ws_session = std::dynamic_pointer_cast(session.second); 54 | if (ws_session) 55 | { 56 | std::scoped_lock ws_locker(ws_session->_ws_send_lock); 57 | 58 | if (ws_session->_ws_handshaked) 59 | ws_session->SendAsync(buffer, size); 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | 66 | } // namespace WS 67 | } // namespace CppServer 68 | -------------------------------------------------------------------------------- /source/server/ws/wss_server.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | \file wss_server.cpp 3 | \brief WebSocket secure server implementation 4 | \author Ivan Shynkarenka 5 | \date 27.05.2019 6 | \copyright MIT License 7 | */ 8 | 9 | #include "server/ws/wss_server.h" 10 | 11 | namespace CppServer { 12 | namespace WS { 13 | 14 | bool WSSServer::CloseAll(int status, const void* buffer, size_t size) 15 | { 16 | std::scoped_lock locker(_ws_send_lock); 17 | 18 | PrepareSendFrame(WS_FIN | WS_CLOSE, false, buffer, size, status); 19 | if (!Multicast(_ws_send_buffer.data(), _ws_send_buffer.size())) 20 | return false; 21 | 22 | return HTTPSServer::DisconnectAll(); 23 | } 24 | 25 | bool WSSServer::CloseAll(int status, std::string_view text) 26 | { 27 | std::scoped_lock locker(_ws_send_lock); 28 | 29 | PrepareSendFrame(WS_FIN | WS_CLOSE, false, text.data(), text.size(), status); 30 | if (!Multicast(_ws_send_buffer.data(), _ws_send_buffer.size())) 31 | return false; 32 | 33 | return HTTPSServer::DisconnectAll(); 34 | } 35 | 36 | bool WSSServer::Multicast(const void* buffer, size_t size) 37 | { 38 | if (!IsStarted()) 39 | return false; 40 | 41 | if (size == 0) 42 | return true; 43 | 44 | assert((buffer != nullptr) && "Pointer to the buffer should not be null!"); 45 | if (buffer == nullptr) 46 | return false; 47 | 48 | std::shared_lock locker(_sessions_lock); 49 | 50 | // Multicast all WebSocket sessions 51 | for (auto& session : _sessions) 52 | { 53 | auto wss_session = std::dynamic_pointer_cast(session.second); 54 | if (wss_session) 55 | { 56 | std::scoped_lock ws_locker(wss_session->_ws_send_lock); 57 | 58 | if (wss_session->_ws_handshaked) 59 | wss_session->SendAsync(buffer, size); 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | 66 | } // namespace WS 67 | } // namespace CppServer 68 | -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 26.05.2016 3 | // 4 | 5 | #include "test.h" 6 | -------------------------------------------------------------------------------- /tests/test.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 26.05.2016 3 | // 4 | 5 | #include 6 | -------------------------------------------------------------------------------- /tests/test_timer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Ivan Shynkarenka on 16.08.2018 3 | // 4 | 5 | #include "test.h" 6 | 7 | #include "server/asio/timer.h" 8 | #include "threads/thread.h" 9 | 10 | using namespace CppCommon; 11 | using namespace CppServer::Asio; 12 | 13 | namespace { 14 | 15 | class AsioTimer : public Timer 16 | { 17 | public: 18 | using Timer::Timer; 19 | 20 | protected: 21 | void onTimer(bool aborted) override 22 | { 23 | if (aborted) 24 | canceled = true; 25 | else 26 | expired = true; 27 | } 28 | 29 | void onError(int error, const std::string& category, const std::string& message) override { errors = true; } 30 | 31 | public: 32 | std::atomic canceled{false}; 33 | std::atomic expired{false}; 34 | std::atomic errors{false}; 35 | }; 36 | 37 | } // namespace 38 | 39 | TEST_CASE("Asio timer test", "[CppServer][Timer]") 40 | { 41 | // Create and start Asio service 42 | auto service = std::make_shared(); 43 | REQUIRE(service->Start()); 44 | while (!service->IsStarted()) 45 | Thread::Yield(); 46 | 47 | // Create Asio timer 48 | auto timer = std::make_shared(service); 49 | 50 | // Setup and synchronously wait for the timer 51 | timer->Setup(UtcTime() + Timespan::seconds(1)); 52 | timer->WaitSync(); 53 | 54 | // Setup and asynchronously wait for the timer 55 | timer->Setup(Timespan::seconds(1)); 56 | timer->WaitAsync(); 57 | 58 | // Wait for a while... 59 | Thread::Sleep(2000); 60 | 61 | // Setup and asynchronously wait for the timer 62 | timer->Setup(Timespan::seconds(1)); 63 | timer->WaitAsync(); 64 | 65 | // Wait for a while... 66 | Thread::Sleep(500); 67 | 68 | // Cancel the timer 69 | timer->Cancel(); 70 | 71 | // Wait for a while... 72 | Thread::Sleep(500); 73 | 74 | // Stop the Asio service 75 | REQUIRE(service->Stop()); 76 | while (service->IsStarted()) 77 | Thread::Yield(); 78 | 79 | // Check the timer state 80 | REQUIRE(timer->canceled); 81 | REQUIRE(timer->expired); 82 | REQUIRE(!timer->errors); 83 | } 84 | -------------------------------------------------------------------------------- /tools/certificates/ca-secret.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tools/certificates/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 33 | NC3uMWWz3A== 34 | -----END CERTIFICATE----- 35 | -------------------------------------------------------------------------------- /tools/certificates/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tools/certificates/ca.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/tools/certificates/ca.pfx -------------------------------------------------------------------------------- /tools/certificates/client-secret.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tools/certificates/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFcTCCA1kCAQEwDQYJKoZIhvcNAQELBQAweTELMAkGA1UEBhMCQlkxEDAOBgNV 3 | BAgMB0JlbGFydXMxDjAMBgNVBAcMBU1pbnNrMRgwFgYDVQQKDA9FeGFtcGxlIHJv 4 | b3QgQ0ExGDAWBgNVBAsMD0V4YW1wbGUgQ0EgdW5pdDEUMBIGA1UEAwwLZXhhbXBs 5 | ZS5jb20wHhcNMTkwNjAxMTI1MjQ1WhcNMjkwNTI5MTI1MjQ1WjCBgzELMAkGA1UE 6 | BhMCQlkxEDAOBgNVBAgMB0JlbGFydXMxDjAMBgNVBAcMBU1pbnNrMRcwFQYDVQQK 7 | DA5FeGFtcGxlIGNsaWVudDEcMBoGA1UECwwTRXhhbXBsZSBjbGllbnQgdW5pdDEb 8 | MBkGA1UEAwwSY2xpZW50LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC 9 | Ag8AMIICCgKCAgEAyG7fNpmwFMip2daVMWleNfQ4djHJpAD3CY4PFL+CDU3MRwve 10 | QWyX04iOpInhRk8pTsPisWCqouBxmo14jprAOv5XVEm4eHTcvxQ1UsUBPSzF3h1o 11 | Uy2PuOnd803N1ja239z2jAMbdNwnihz9SoNT9i5wD3rDUK3vbUx1i8ixC/wX0RMI 12 | Vb1RtE+dCbyhsiXTesotB2uqzd4cDl0gLBmD9+lOlPKA5Qx3bzFJAjr7YlPEBL7J 13 | CL+bj+fC2lX7Hbn3tj3fPtgHjuglIL26WM8K8OYDdM2fq2X0XfPTcJasqxxs3+Bw 14 | 5P/7hXRx+Su2gEaNa0TlAwa+PL28TKmGYppP6mEKG97P/fR45Uw1Nv7SNFXP8awQ 15 | 3T610ViLm+krj3AsE7hr5JwRCPbedQvHm2mrQ+onv6Xtm8PDzbuqpAHltUQWBmnc 16 | dcByH42ugeGQmajwM/4hZVPpPhk7+67HFCUN/Qs1HX2KnJJ9M++sMt5Le6nk9bVo 17 | YSoKXwmlDPvBiT43gcL+ckk+QjbrpJ6hZFRdPAIJzjFSvsFbAi5Qaxam6J3OWiTq 18 | 3wDqO/GnPFtFvtmpUc9iExRBy772u8mNb2BnEPD2rDnw0bTxuWHkWIo6iQljl8z+ 19 | PxLWtMyxBbcQpa46JrS6Tcdx2WpGSOGOdCpmQ+O2qe2B4u2+/GRJTP5bwQ8CAwEA 20 | ATANBgkqhkiG9w0BAQsFAAOCAgEAgbhW3XJDV/j8TNZLVlH2U4ocmdUUO8xT4sqw 21 | S1SzGrL7t6PA2Lus/LCnbOwakq12SzuH2YmTE4y7wXY/313kmYcn220qohdEgxBk 22 | JTNdSvQ6/k1FgJcqCoMLHq6+J8fpW7cYrigHknK+gvKMFoE/cPVAADn1KaRg08LP 23 | fbg4Fmi0ZAvf5VT0KqlfgodORoruiDj0y2nnX7HGKy59mzNteJTescvwt2uDvuhF 24 | xtWsPP/vyYE+XGuaJTxIYUiPhsjVuC91P6Jj8UZo4IJrBSrtbMv2TkvBYh2NstDN 25 | gCDef8ESu3rv9O+UWJh5QdSnY8NFoAe2ZtItjQ1zGXT1DFtd2OAFQUW0z7E4IgRQ 26 | DppXhY2xdcNP4sQibytGfqC8Qi0DexWtLPXVPj7J25Cvw9q7/FkqwKbN3RxB8WA0 27 | nen4VHW6SqPxQfdlmDQuxQymwhONPDI1YBjsQ569c9d2k67xulyadLNPhtLDG/NR 28 | jh6y+hB/NXZyPDqQM+/IsqvvQnGUHmssmaF9udYo6JfJx6YfaFkJeGE1P6+67lJi 29 | wFXaXWtr26QgsNQXBgqKpwk9bo2S8JFObPAJTCSCRFaXOtB/kApQ+mTxamG2ycyd 30 | fg5p4Ef30Nfj3/oHdbw7aj3O1xj/4y6HfT1cLV/A1t9LJ7kO134rHao2NRuvughr 31 | 5kfERrg= 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /tools/certificates/client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEyTCCArECAQAwgYMxCzAJBgNVBAYTAkJZMRAwDgYDVQQIDAdCZWxhcnVzMQ4w 3 | DAYDVQQHDAVNaW5zazEXMBUGA1UECgwORXhhbXBsZSBjbGllbnQxHDAaBgNVBAsM 4 | E0V4YW1wbGUgY2xpZW50IHVuaXQxGzAZBgNVBAMMEmNsaWVudC5leGFtcGxlLmNv 5 | bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMhu3zaZsBTIqdnWlTFp 6 | XjX0OHYxyaQA9wmODxS/gg1NzEcL3kFsl9OIjqSJ4UZPKU7D4rFgqqLgcZqNeI6a 7 | wDr+V1RJuHh03L8UNVLFAT0sxd4daFMtj7jp3fNNzdY2tt/c9owDG3TcJ4oc/UqD 8 | U/YucA96w1Ct721MdYvIsQv8F9ETCFW9UbRPnQm8obIl03rKLQdrqs3eHA5dICwZ 9 | g/fpTpTygOUMd28xSQI6+2JTxAS+yQi/m4/nwtpV+x2597Y93z7YB47oJSC9uljP 10 | CvDmA3TNn6tl9F3z03CWrKscbN/gcOT/+4V0cfkrtoBGjWtE5QMGvjy9vEyphmKa 11 | T+phChvez/30eOVMNTb+0jRVz/GsEN0+tdFYi5vpK49wLBO4a+ScEQj23nULx5tp 12 | q0PqJ7+l7ZvDw827qqQB5bVEFgZp3HXAch+NroHhkJmo8DP+IWVT6T4ZO/uuxxQl 13 | Df0LNR19ipySfTPvrDLeS3up5PW1aGEqCl8JpQz7wYk+N4HC/nJJPkI266SeoWRU 14 | XTwCCc4xUr7BWwIuUGsWpuidzlok6t8A6jvxpzxbRb7ZqVHPYhMUQcu+9rvJjW9g 15 | ZxDw9qw58NG08blh5FiKOokJY5fM/j8S1rTMsQW3EKWuOia0uk3HcdlqRkjhjnQq 16 | ZkPjtqntgeLtvvxkSUz+W8EPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAcBC/ 17 | 68GhRRHZ3LE1/ik8Y9FoHsIW02gmVSNXbjCWxhklXR+t8fq9Oc7IhaKGTAXYGH/D 18 | PGpGMSpzsdPKilvPRm/IrOJ93rMtfWtQ+x9ksTsgZw72GlNB9ccryjqZIRCK/1Up 19 | Pyi28TFrb085kP6mrIqk5dQpL7Zpi1XYe6Nh6r/IrLllyNi7noZhyKbBSp+urzTS 20 | WpI8K1p6/ivX3eZ5ZCAqca5kb9Qi7aXOUQ1OV7OZkOPTXtUMiMAzk1UC4Bvsg9MR 21 | S0jTiUIktTFZSRfBPZ/S/ZHsTg7iPtgTmKAGbZSBiMsuWbqafdI5NDa8wzSOrLTB 22 | uoD723L+t1Z57Trv69nkJQmqJTwz3mDDdSoEF6rUMywYZsAJBS8HH0ckrvrFZN88 23 | afV3FEeIDAKtZuGJS4rPxSzDWrnguqK76ocXOdDm5ILgWAX5Lhwog4UattKpAm8y 24 | HiWO6M1Q8/UsleZSKLHLs5VMFSg1854W9Gxdx/nVfnKOAlg/ldd1g5yY/H+rHjBl 25 | QXgwcLsBrQ3xZ+1beJi2AWhPcpr3MlguLocX3VXIxiY5pK4O9bscN+BuNVFTeZbV 26 | paoTsnad2wZKpQcJEsC+q2lwrbCuzP63aw1mn3Rhfa1XLYRR87Fu4V4DIzLRexwS 27 | mqvlo9Lf+E/y/TxryhOqcb0VZJHFJ2vhxqABSQI= 28 | -----END CERTIFICATE REQUEST----- 29 | -------------------------------------------------------------------------------- /tools/certificates/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tools/certificates/client.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/tools/certificates/client.pfx -------------------------------------------------------------------------------- /tools/certificates/dh4096.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIICCAKCAgEA3vn3BRdZq7LQFwt94mhU6oZdPKSsrO4Iylb3FVEp4BY4JNGKAANc 3 | m1nFkCTSTLonQBNyDmfYPh1aHaXhl1J7QOGDMo+ydMNnsRDv72iuwJxb2RFC2pb7 4 | B1mbgkzHFW0xcMefIAnvYXxS5tcPV1zoxYAeo75YsJXb7NxBquW45py/0W3Tf8lB 5 | Ml60GjRSA9bnlS8hLDbz/Y0i2Fp01MH4Isq0EvaYn/BckBJpfMGDI67+cjeSfZY9 6 | +FV9po0qNVV8kl8D0oSWp1xBSigNuKb0x/XloW9zlrNClpHlFU46gbvlNA3E57w7 7 | B4OUTUHuMYVmVnxIAngJLTXAD9iii+Am979qiJbZMgwA1iGxtsPxS5/dyzYfFSp4 8 | dfQnMNvuxRzJyYtk8Q/pZZxNdDhlKlIPpF1UlXQwoO4ppOOCUndAIomzMyP2/Up4 9 | FlYd1Cgo9rg3FKyGBxbQtwS8JhthJrqjnhiI/eaSyzP9aNFl0YsTfCMeMOtfgWia 10 | BoD4BFvsuBZa+YFE0un2d7uSAHdCq7BCY2kNu+kD7jVp6bh9ZcZayWnZZy/1Gp1E 11 | ChvXuaFwfqwNBTde7HlR1mBg3LYHvG41yNgdAabSAudTdUVkrWQM9yjSdMFYciVe 12 | ncyqkwNnZhcMf/CeBFx3fJndJih25N8lIMhNkSXUQ507Idh5MUV1DbMCAQI= 13 | -----END DH PARAMETERS----- 14 | -------------------------------------------------------------------------------- /tools/certificates/generate.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/tools/certificates/generate.bat -------------------------------------------------------------------------------- /tools/certificates/generate.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/tools/certificates/generate.sh -------------------------------------------------------------------------------- /tools/certificates/server-secret.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJJwIBAAKCAgEAtdVvGlBsP+78L+bpRgvPdti+AVgM1JCMP7mOHvv3m+x0gIp1 3 | j/Sg/S0h/leYsPu7H2k5xv41Y4fmWPX7u0xPLdI+/u1zHHc6IGEaM0aEddEruDUr 4 | QcQt+h62c/nIJ+tcXuSHrTZREbczZq4gm7exvAuvYd0B/lg2kXLQ9Y7eqShhKPtH 5 | B6a5YH2snJWJbk8E9WVwem37nrH5DJ99/q+hQHl9rdrP03KAEIbMLGgo3r2YuOoa 6 | 7qoywusyH9xMpWzDt0QhXxhfmWnSNyZG8ztfoXt6TDTZQ2HD/H/dZlt3skgJAWcU 7 | tlF4l0tZ55495SC4ozFyk84tNJPBD/QkRYmn3GfJ1zHgdFru+H2qYHJv5B4ssUbS 8 | cPkXwcsASci/JiyIbhPzOpbpCTUGX3OAMBKIFtxJNKmHeosftR9I97dNfJZCCiC7 9 | k5NL8GaTw0484tLqfuH1bOmUULsfLaEj6rsiXLz9uB8T16/K9pKf2LIB++eCEU71 10 | S4n6BHyiH09uL1KZ0msc5beggUiUglCUYy31aIFuZl/wCuH8GJZv0kepAWLIL23h 11 | PwpzS5o+tZHefwS//qG8mcy7a+NcLlIsLNPRVToYmlcNnfeAxcDqwRm2GKfAY4i7 12 | CUt4vgyEGbFxBNsh6ozTkd9tE3qkRtpMRKcX3ZQmYJNjEOl7XCnUk9SLMOECAwEA 13 | AQKCAgBb3rJ7wRZwVvbj3O8PjPgNPAUD+NDCtSWnLME5tmSsSxOxvkMXsKmGQT9j 14 | mi5zfTxV6nxepiGjYA5p9B5zy2JV7FwXwTDfuP2NToJGVeKnBD/qmjJ4z/3K2aml 15 | fxY51RieeShzw3XCVaWKw3+GLZGHSQAbmeZf84Heivw4lS66mMQ+SHbizsHqlpSX 16 | qJX/Pb1rnwztTpRK4fDLB+pIu8PlJ3zwUhWe58L8lp6h8R51K6X2B5ID88oh4WM5 17 | 5bxz+DgKaEnUGiRzBpxHcPd3/Q+cLx7jUfBTsxmqgZADH0Oit/KU2tgEJbWf+1o5 18 | RCJRme6vxVP2ib0dS2nH/bo1yA8e2uGu5n7ZRxEdmA7wNGsxokBp5ifAOtsVGwEP 19 | CmKD6+kRVlb5zEc+jGsZISpra/3CL42eM1vLGaY9bVBhVrW5YyOyvaK0S6vjzPsf 20 | T2rqWpgZ7y+bAwfGgkKM7AJOJ2NMGuLkcdiWfKQsL3UdMKSsplk+rnEB/c339AxX 21 | +Y07rYMX68mp8vBYsbZQmLwO/25Wbba18jIzkqlHYrk7vhW4U5X2A6QULfrvp3/W 22 | 10Voae61GznWKJ8be8iK3Hf3Qw6xirQayj66wRdJjmAwv7+hwdIDY10wregKqtut 23 | 64g3FPgYmyxk2PmD7dRbVeWdxod3LKfA4wRYJ7t0Lj2V3n/sgQKCAQEA3B5VfB// 24 | t0hjZM4tRWUn9oDb1qrtzAM+2KR4Td+CQDk7eEVfZNuOORZLii8irmtCcFSsOTtV 25 | zQcIf4wZU0xIpeFkUit+QxqZogMI+IIA6JzQwmiCMWyb40pLO3v1EA5K6EAXhSTM 26 | EZBYyycsYtQKUp7gv/dq5H4XmpQVb4ZDfoo2zqYAAHOmg76lRXopeWAvtN2of+PJ 27 | A6+F24xcDARo3BrMRC7nHxwgLCm6gJzt09xnG4cMlix0aTT23y/7CuS7NZFHKITv 28 | DMzJ5Ye5gU8TVh902/LAiy6MjVbTXjhcRerHUnhg4r47vsB653yXnMYIEmYC7s+/ 29 | GHdQqS7mTK0oBQKCAQEA03l0qHimEvaknNCCEkvRJGCXWeAWXE718SLGsPsdeMup 30 | nQmUacWmX//eYKk3RrlzJr7tABW6EeTJ6enoC9/tLNQD/sOm3Eh5pRd3o+Re33Xo 31 | 8uHh+mAqCM8jeaPMhkQZww8m168HAC4N4uxMRcOFAqB5ys3BHJvbjJsWwX86uoaw 32 | tf8cK59P5e7lJzVhQ0sEgQGHcIeqquzvqSHxYgp55l+g8Hf1MI7qWCD+Gt86HDzZ 33 | kNsNqHJcJdHPr9MI8KXuvgl6aGoXIvit8XQ7Hg8OtX0ExqGoeNjBNyIyifk9ydtO 34 | 3of4mXy0q29yTzV0Kt/cZvp2bG+7Hd5JJ5GLa18ILQKCAQAG5FxA2q+jCX0zNtFs 35 | DtLFgRthCVEQxjk9h0jNB2aIpEIcbe+itM0rNGuBFCC93VXjNoN990GkfcfiVnyk 36 | gwrzRq9hc0MszrRowjeRsGBe6CoRLDyHV6M55qWcYzE1I31s8DTMUm6hTie5lKxr 37 | G8CG/bqDyDdsmBYdHO3e5BFQ8PruVXxCh1x7W4jJOB38UuqrexU/i95LYz+JtEdd 38 | iPXPjnc+20kZTEQlndjdFgzMSWZhEkVunk22zZW9Pz9ZA/hooPfdaOwjNnZL3YgN 39 | aHBujeWWzW8B7J8x/bn4hUM+XS+IgYRnFRXBzz0J6njEy96M1OzalV6iYXoBEhrb 40 | 48ARAoIBABcIaX5X9a6nEnLJ+wDHJTZTFukBES5oozzqTr3D/AfGFuk1u+ZxUpeu 41 | JKhehdi8JiCYNvQFaci9JIjHozB36TsytGSxJqFje2xRzAQbwYGRNBgQJi7A/pML 42 | DJAZGROeozetlMt1EswgN/75Qa1viDMrC1jdZCUbjKQZ2DanBtx+Aw0vhf/yUB95 43 | D5hfpgJQT2NFqVzGSf5n5AqF2eaVwYUn8T1/s0LgrgF/Rm3i1k9xCTlPwoMQQZ0U 44 | 5wv9bkHXsNMd8SkiNPboIvnjcPTrKuz1eumvfcv7v7+jh+GjNemga0ytfpQpEvyB 45 | HPAnoElzLGxC51cULEsqhMk8fvTo2tkCggEAWGVqTvBZOW/HH9F56eXU+N4EFbDd 46 | QAJbY7uGnpUWzlfz7idUmCxVgTZ+qLwQGvebD+EVINiT3mWXl25nWWSDArMGMLtq 47 | UD9GB9RuY6xA3drK0mW0EMuUzU6Qxq3AYUEKhSXiRjipCD0fIZbq7hBMQ+a1Tj2P 48 | phVxgVMA+z1AEyQy1LogNuXy/0LfYoFisqQfwzwqlLYcd6jdsGrp53NM8GogRCSV 49 | x0vMddjjnZhbVnukmPWZfasuOstBy9PcB5uzvQzDLAv59Yho/RD4sqamPXQpbY3S 50 | aqhG8KD/fYudFbY0J06VESq2bL/ZpMMPK9MJgmcLVXcR/MBjoXUI24PzAg== 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tools/certificates/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFcTCCA1kCAQEwDQYJKoZIhvcNAQELBQAweTELMAkGA1UEBhMCQlkxEDAOBgNV 3 | BAgMB0JlbGFydXMxDjAMBgNVBAcMBU1pbnNrMRgwFgYDVQQKDA9FeGFtcGxlIHJv 4 | b3QgQ0ExGDAWBgNVBAsMD0V4YW1wbGUgQ0EgdW5pdDEUMBIGA1UEAwwLZXhhbXBs 5 | ZS5jb20wHhcNMTkwNjAxMTI1MjQ0WhcNMjkwNTI5MTI1MjQ0WjCBgzELMAkGA1UE 6 | BhMCQlkxEDAOBgNVBAgMB0JlbGFydXMxDjAMBgNVBAcMBU1pbnNrMRcwFQYDVQQK 7 | DA5FeGFtcGxlIHNlcnZlcjEcMBoGA1UECwwTRXhhbXBsZSBzZXJ2ZXIgdW5pdDEb 8 | MBkGA1UEAwwSc2VydmVyLmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOC 9 | Ag8AMIICCgKCAgEAtdVvGlBsP+78L+bpRgvPdti+AVgM1JCMP7mOHvv3m+x0gIp1 10 | j/Sg/S0h/leYsPu7H2k5xv41Y4fmWPX7u0xPLdI+/u1zHHc6IGEaM0aEddEruDUr 11 | QcQt+h62c/nIJ+tcXuSHrTZREbczZq4gm7exvAuvYd0B/lg2kXLQ9Y7eqShhKPtH 12 | B6a5YH2snJWJbk8E9WVwem37nrH5DJ99/q+hQHl9rdrP03KAEIbMLGgo3r2YuOoa 13 | 7qoywusyH9xMpWzDt0QhXxhfmWnSNyZG8ztfoXt6TDTZQ2HD/H/dZlt3skgJAWcU 14 | tlF4l0tZ55495SC4ozFyk84tNJPBD/QkRYmn3GfJ1zHgdFru+H2qYHJv5B4ssUbS 15 | cPkXwcsASci/JiyIbhPzOpbpCTUGX3OAMBKIFtxJNKmHeosftR9I97dNfJZCCiC7 16 | k5NL8GaTw0484tLqfuH1bOmUULsfLaEj6rsiXLz9uB8T16/K9pKf2LIB++eCEU71 17 | S4n6BHyiH09uL1KZ0msc5beggUiUglCUYy31aIFuZl/wCuH8GJZv0kepAWLIL23h 18 | PwpzS5o+tZHefwS//qG8mcy7a+NcLlIsLNPRVToYmlcNnfeAxcDqwRm2GKfAY4i7 19 | CUt4vgyEGbFxBNsh6ozTkd9tE3qkRtpMRKcX3ZQmYJNjEOl7XCnUk9SLMOECAwEA 20 | ATANBgkqhkiG9w0BAQsFAAOCAgEAC/W9uU6zNgUzoxP3qCIXgpPPItKzkbQArXK9 21 | MNqWnBM+ccUbaGCUMG/i5dmfT2YeTMC72Z71xb6QznFJHXOuKKVPzLNwVuIR/xwE 22 | j3BeQkUZ33Kf8TUxz5owHV9Px944KiEwhIOyPjgbG9WPL5IsXMBMLZi4EAVOza7T 23 | lqykOfgV2kwFEOPD4Sz2bYOxp7eNu+cQAMf/COQrMC2L97OtcrquipRAaY2rxb3Z 24 | pD8r3ymRs14K5rf6LTUrxrCIeZewxLyX8FedBZPCUCRLb7lsu1r7OHtbt+xUy+7i 25 | KtmEqgLpJ9Iu8xK4rf8ReLkgT5SownaGI+ddYdyB5aiR2DgLXKxGQZ6l6sznkzDk 26 | X2UZAtzhTxRaZ8wHMmR5z7q/F8EM+PR0a1Y5Of+Yosv9dTERMyNosnd9EHXTbgSo 27 | ARaPso0J9V3jXm44+qd4pHgnLr7SOp3B5Jf71yhN1p5fKYqPkbiCiZFxOXO3s5z6 28 | +4247z7ZCD7k9UMqKflj4eLQD+OnTJ6VFyrovTQnjCsbTsEmI1S8arvAEosAX5GU 29 | vR05YZnEO9rEzOSh9tBuuht8woK5tQpLQwksgOiQATcZCN/ioz1SmyrRIfwEBh66 30 | MB4SMwGjiaARsWhV+iEpS8mwvI1WtX/4Xgo7NropbFyIuJsZsmvDfuffqp9Z8f/b 31 | kYDiTio= 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /tools/certificates/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEyTCCArECAQAwgYMxCzAJBgNVBAYTAkJZMRAwDgYDVQQIDAdCZWxhcnVzMQ4w 3 | DAYDVQQHDAVNaW5zazEXMBUGA1UECgwORXhhbXBsZSBzZXJ2ZXIxHDAaBgNVBAsM 4 | E0V4YW1wbGUgc2VydmVyIHVuaXQxGzAZBgNVBAMMEnNlcnZlci5leGFtcGxlLmNv 5 | bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALXVbxpQbD/u/C/m6UYL 6 | z3bYvgFYDNSQjD+5jh7795vsdICKdY/0oP0tIf5XmLD7ux9pOcb+NWOH5lj1+7tM 7 | Ty3SPv7tcxx3OiBhGjNGhHXRK7g1K0HELfoetnP5yCfrXF7kh602URG3M2auIJu3 8 | sbwLr2HdAf5YNpFy0PWO3qkoYSj7RwemuWB9rJyViW5PBPVlcHpt+56x+Qyfff6v 9 | oUB5fa3az9NygBCGzCxoKN69mLjqGu6qMsLrMh/cTKVsw7dEIV8YX5lp0jcmRvM7 10 | X6F7ekw02UNhw/x/3WZbd7JICQFnFLZReJdLWeeePeUguKMxcpPOLTSTwQ/0JEWJ 11 | p9xnydcx4HRa7vh9qmByb+QeLLFG0nD5F8HLAEnIvyYsiG4T8zqW6Qk1Bl9zgDAS 12 | iBbcSTSph3qLH7UfSPe3TXyWQgogu5OTS/Bmk8NOPOLS6n7h9WzplFC7Hy2hI+q7 13 | Ily8/bgfE9evyvaSn9iyAfvnghFO9UuJ+gR8oh9Pbi9SmdJrHOW3oIFIlIJQlGMt 14 | 9WiBbmZf8Arh/BiWb9JHqQFiyC9t4T8Kc0uaPrWR3n8Ev/6hvJnMu2vjXC5SLCzT 15 | 0VU6GJpXDZ33gMXA6sEZthinwGOIuwlLeL4MhBmxcQTbIeqM05HfbRN6pEbaTESn 16 | F92UJmCTYxDpe1wp1JPUizDhAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAOiyt 17 | IFW99oEKt3GynnA4qyo1ppaQVOdhErqE7VzOOLUEMYsHfIOOQexLNzmRUwjgZ6cj 18 | h8ee5qrPSmG+s4nLos08LNTi61edFSb2wiL8GwUJo9PhraWjQdB/SJLjaJ1UIILS 19 | 0C11M+IdHNSgriW1OKdeAV0rj7391MhTNl/7FeAqhYw7geVfOuO7c3DxLt0Ce07K 20 | Qcf/1jt4vm8SzY1evZKfd4Spapgpo1FMpMbA/ymxX7eI8lbOxYSCE8rwf0ojGzhN 21 | bCs0Lu9oby+LA23EPB/1aMCXMnuKBdstX9I1iFXqjSl9Ljiz+ShKYgeM9atWNtyW 22 | FsFcl39S0vFrdVhcAiIiC0PxjEAxGRKFjyuSxhjBLUcv91WZMfexqS8FkamlX/t6 23 | VKUS9VUW7fK6AFXvrGOMbpvoxBtEcYcU71Wj16I1GSXn4u2/VzwL2xGTqMRVRdvc 24 | INwAOqEzgi4FEeT86V7kuKmAfr5s67y3Kprpkfz9xW1sfU58qDjntIXrD+GynUzS 25 | 2H9BL44LlJMtxs7IYV1RO+Po0zFYlUWY8M951PIpvRSXYGX0uTH8GFHiltQQpiIo 26 | +fpwkJw8R7iq6K4Z3M0iL9ZtACC6lGYDnH2PZXUbMXijCcvkN8Fm9knewOR+x7FQ 27 | KRv51X528kMxA5FB9ZEBPMbh2gxppoBe3275svM= 28 | -----END CERTIFICATE REQUEST----- 29 | -------------------------------------------------------------------------------- /tools/certificates/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tools/certificates/server.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/tools/certificates/server.pfx -------------------------------------------------------------------------------- /www/api/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore swagger directory 2 | swagger 3 | -------------------------------------------------------------------------------- /www/api/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Swagger UI 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /www/api/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | 3 | info: 4 | version: 1.0 5 | title: HTTP Cache Server API 6 | description: HTTP Cache Server API 7 | contact: 8 | name: chronoxor 9 | url: https://github.com/chronoxor/CppServer 10 | email: chronoxor@gmail.com 11 | 12 | servers: 13 | - url: /api 14 | description: Cache API 15 | 16 | tags: 17 | - name: Cache 18 | description: Cache methods 19 | 20 | paths: 21 | /cache: 22 | get: 23 | tags: 24 | - Cache 25 | summary: Get the cache value 26 | operationId: GetCacheValue 27 | parameters: 28 | - name: key 29 | in: query 30 | description: Cache key (optional) 31 | required: false 32 | schema: 33 | type: string 34 | example: 'test' 35 | responses: 36 | 200: 37 | description: Success 38 | content: 39 | application/json: 40 | schema: 41 | $ref: '#/components/schemas/CacheItems' 42 | text/plain: 43 | schema: 44 | type: string 45 | 404: 46 | description: Cache key not found 47 | content: {} 48 | 500: 49 | description: Internal server error 50 | content: {} 51 | post: 52 | tags: 53 | - Cache 54 | summary: Create the cache value 55 | operationId: CreateCacheValue 56 | parameters: 57 | - name: key 58 | in: query 59 | description: Cache key 60 | required: true 61 | schema: 62 | type: string 63 | example: 'test' 64 | requestBody: 65 | description: Cache value to create 66 | required: true 67 | content: 68 | text/plain: 69 | schema: 70 | type: string 71 | example: 'value' 72 | responses: 73 | 200: 74 | description: Success 75 | content: {} 76 | 500: 77 | description: Internal server error 78 | content: {} 79 | put: 80 | tags: 81 | - Cache 82 | summary: Modify the cache value 83 | operationId: ModifyCacheValue 84 | parameters: 85 | - name: key 86 | in: query 87 | description: Cache key 88 | required: true 89 | schema: 90 | type: string 91 | example: 'test' 92 | requestBody: 93 | description: Cache value to modify 94 | required: true 95 | content: 96 | text/plain: 97 | schema: 98 | type: string 99 | example: 'modified' 100 | responses: 101 | 200: 102 | description: Success 103 | content: {} 104 | 500: 105 | description: Internal server error 106 | content: {} 107 | delete: 108 | tags: 109 | - Cache 110 | summary: Delete the cache value 111 | operationId: DeleteCacheValue 112 | parameters: 113 | - name: key 114 | in: query 115 | description: Cache key 116 | required: true 117 | schema: 118 | type: string 119 | example: 'test' 120 | responses: 121 | 200: 122 | description: Success 123 | content: 124 | text/plain: 125 | schema: 126 | type: string 127 | 404: 128 | description: Cache key not found 129 | content: {} 130 | 500: 131 | description: Internal server error 132 | content: {} 133 | head: 134 | tags: 135 | - Cache 136 | summary: Get the cache headers 137 | operationId: GetCacheHeaders 138 | responses: 139 | 200: 140 | description: Success 141 | content: {} 142 | 500: 143 | description: Internal server error 144 | content: {} 145 | options: 146 | tags: 147 | - Cache 148 | summary: Get the cache options 149 | operationId: GetCacheOptions 150 | responses: 151 | 200: 152 | description: Success 153 | content: {} 154 | 500: 155 | description: Internal server error 156 | content: {} 157 | 158 | components: 159 | schemas: 160 | CacheItem: 161 | type: object 162 | properties: 163 | key: 164 | type: string 165 | value: 166 | type: string 167 | CacheItems: 168 | type: array 169 | items: 170 | $ref: '#/components/schemas/CacheItem' 171 | -------------------------------------------------------------------------------- /www/api/swagger.js: -------------------------------------------------------------------------------- 1 | window.onload = function() { 2 | // 3 | 4 | // the following lines will be replaced by docker/configurator, when it runs in a docker-container 5 | window.ui = SwaggerUIBundle({ 6 | url: "openapi.yaml", 7 | defaultModelsExpandDepth: 0, 8 | displayRequestDuration: true, 9 | dom_id: '#swagger-ui', 10 | deepLinking: true, 11 | presets: [ 12 | SwaggerUIBundle.presets.apis, 13 | SwaggerUIStandalonePreset 14 | ], 15 | plugins: [ 16 | SwaggerUIBundle.plugins.DownloadUrl 17 | ], 18 | layout: "StandaloneLayout" 19 | }); 20 | 21 | // 22 | }; 23 | -------------------------------------------------------------------------------- /www/ws/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/www/ws/favicon.png -------------------------------------------------------------------------------- /www/ws/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket chat client example 6 | 7 | 8 | 9 | 86 |
87 |

88 | 89 |

90 |

91 | 92 | 93 |

94 |

95 | 96 |

97 |

98 | 99 |

100 |

101 | 102 | 103 |

104 |
105 | 106 | 107 | -------------------------------------------------------------------------------- /www/wss/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chronoxor/CppServer/08b1937193e676f4c286512093a77d93bc26f54a/www/wss/favicon.png -------------------------------------------------------------------------------- /www/wss/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket chat client example 6 | 7 | 8 | 9 | 86 |
87 |

88 | 89 |

90 |

91 | 92 | 93 |

94 |

95 | 96 |

97 |

98 | 99 |

100 |

101 | 102 | 103 |

104 |
105 | 106 | 107 | --------------------------------------------------------------------------------