From cc78c4abe7bd78babcf953d7b19261837c466cfc Mon Sep 17 00:00:00 2001 From: milek7 Date: Fri, 4 Aug 2023 01:28:24 +0200 Subject: [PATCH 01/14] ci --- .github/workflows/ci.yml | 75 +++++++++++++++++++++++++++++++++++++ .github/workflows/cmake.yml | 40 -------------------- DMI/CMakeLists.txt | 4 ++ EVC/CMakeLists.txt | 3 ++ wasi-sdk.cmake | 8 ++-- 5 files changed, 86 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/cmake.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..56dea432 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,75 @@ +name: CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build_win: + name: Build for Win64 + + strategy: + matrix: + sr_flag: ["ON", "OFF"] + + runs-on: windows-2022 + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Configure + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release -A x64 -DSIMRAIL=${{matrix.sr_flag}} + + - name: Build + run: cmake --build ${{github.workspace}}/build --config Release + + - name: Publish + uses: actions/upload-artifact@3 + with: + name: build-win64-sr${{matrix.sr_flag}} + path: | + ${{github.workspace}}/build/DMI/Release + ${{github.workspace}}/build/EVC/Release + + build_wasm: + name: Build for WASM + + strategy: + matrix: + sr_flag: ["ON", "OFF"] + + runs-on: ubuntu-22.04 + + steps: + - name: Setup wasi-sdk + run: | + mkdir -p ${{github.workspace}}/wasi-sdk + cd ${{github.workspace}}/wasi-sdk + export WASI_VERSION=20 + export WASI_VERSION_FULL=${WASI_VERSION}.0 + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz + tar xvf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz --strip-components=1 + + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Configure + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release -DSIMRAIL=${{matrix.sr_flag}} -DWASI_HOST_EXE_SUFFIX= -DWASI_SDK_PREFIX=${{github.workspace}}/wasi-sdk -DCMAKE_TOOLCHAIN_FILE=wasi-sdk.cmake + + - name: Build + run: cmake --build ${{github.workspace}}/build --config Release + + - name: Publish + uses: actions/upload-artifact@3 + with: + name: build-wasm-sr${{matrix.sr_flag}} + path: | + ${{github.workspace}}/build/DMI/dmi.wasm + ${{github.workspace}}/build/EVC/evc.wasm diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml deleted file mode 100644 index a5253631..00000000 --- a/.github/workflows/cmake.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: CMake - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) - BUILD_TYPE: Debug - -jobs: - build: - # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. - # You can convert this to a matrix build if you need cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - name: Install libasound - run: sudo apt-get install libasound2-dev - - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - - - name: Build - # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - - - name: Test - working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{env.BUILD_TYPE}} - diff --git a/DMI/CMakeLists.txt b/DMI/CMakeLists.txt index 4dfcf91b..2b8b829b 100644 --- a/DMI/CMakeLists.txt +++ b/DMI/CMakeLists.txt @@ -74,6 +74,10 @@ elseif(ANDROID) target_link_libraries(dmi PRIVATE log android GLESv1_CM GLESv2 OpenSLES) endif() +if (WASM) + set_target_properties(dmi PROPERTIES SUFFIX ".wasm") +endif() + if (WITH_SDL AND WIN32) add_custom_command(TARGET dmi POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different diff --git a/EVC/CMakeLists.txt b/EVC/CMakeLists.txt index 3f863c25..42107533 100644 --- a/EVC/CMakeLists.txt +++ b/EVC/CMakeLists.txt @@ -54,3 +54,6 @@ endif() if(ANDROID) target_link_libraries(evc PRIVATE log) endif() +if (WASM) + set_target_properties(evc PROPERTIES SUFFIX ".wasm") +endif() diff --git a/wasi-sdk.cmake b/wasi-sdk.cmake index c8f4f2d4..76d5052a 100644 --- a/wasi-sdk.cmake +++ b/wasi-sdk.cmake @@ -20,10 +20,10 @@ set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_CXX_COMPILER_TARGET ${triple}) set(CMAKE_ASM_COMPILER_TARGET ${triple}) -if(NOT CMAKE_HOST_WIN32) - set(CMAKE_C_FLAGS "--sysroot=/usr/share/wasi-sysroot") - set(CMAKE_CXX_FLAGS "--sysroot=/usr/share/wasi-sysroot") - set(CMAKE_LD_FLAGS "--sysroot=/usr/share/wasi-sysroot") +if(DEFINED WASI_SDK_SYSROOT) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot=${WASI_SDK_SYSROOT}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --sysroot=${WASI_SDK_SYSROOT}") + set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} --sysroot=${WASI_SDK_SYSROOT}") endif() # Don't look in the sysroot for executables to run during the build From e92d6fe0a998c6a4277542355e1855df3cfdc135 Mon Sep 17 00:00:00 2001 From: milek7 Date: Fri, 4 Aug 2023 01:34:20 +0200 Subject: [PATCH 02/14] ci --- .github/workflows/ci.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56dea432..4ceedea2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: run: cmake --build ${{github.workspace}}/build --config Release - name: Publish - uses: actions/upload-artifact@3 + uses: actions/upload-artifact@v3 with: name: build-win64-sr${{matrix.sr_flag}} path: | @@ -46,7 +46,15 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Setup wasi-sdk + - name: Cache wasi-sdk + id: cache-wasi-sdk + uses: actions/cache@v3 + with: + path: ${{github.workspace}}/wasi-sdk + key: wasi-sdk-20 + + - name: Download wasi-sdk + if: steps.cache-wasi-sdk.outputs.cache-hit != 'true' run: | mkdir -p ${{github.workspace}}/wasi-sdk cd ${{github.workspace}}/wasi-sdk @@ -67,7 +75,7 @@ jobs: run: cmake --build ${{github.workspace}}/build --config Release - name: Publish - uses: actions/upload-artifact@3 + uses: actions/upload-artifact@v3 with: name: build-wasm-sr${{matrix.sr_flag}} path: | From cc014be22bd55d18aaf1c4bf55f1d52c3e7353b7 Mon Sep 17 00:00:00 2001 From: milek7 Date: Fri, 4 Aug 2023 01:45:18 +0200 Subject: [PATCH 03/14] ci --- .github/workflows/ci.yml | 14 +++++++------- wasi-sdk.cmake | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ceedea2..dee50633 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,11 @@ jobs: runs-on: ubuntu-22.04 steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Cache wasi-sdk id: cache-wasi-sdk uses: actions/cache@v3 @@ -60,13 +65,8 @@ jobs: cd ${{github.workspace}}/wasi-sdk export WASI_VERSION=20 export WASI_VERSION_FULL=${WASI_VERSION}.0 - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz - tar xvf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz --strip-components=1 - - - name: Checkout - uses: actions/checkout@v3 - with: - submodules: 'recursive' + wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz + tar xf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz --strip-components=1 - name: Configure run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release -DSIMRAIL=${{matrix.sr_flag}} -DWASI_HOST_EXE_SUFFIX= -DWASI_SDK_PREFIX=${{github.workspace}}/wasi-sdk -DCMAKE_TOOLCHAIN_FILE=wasi-sdk.cmake diff --git a/wasi-sdk.cmake b/wasi-sdk.cmake index 76d5052a..e9c70df5 100644 --- a/wasi-sdk.cmake +++ b/wasi-sdk.cmake @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4.0) +cmake_minimum_required(VERSION 3.5.0) set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_VERSION 1) From 0a413f4c5cea1bfb58fd96700c6ffe9a6bdbc61c Mon Sep 17 00:00:00 2001 From: milek7 Date: Fri, 4 Aug 2023 01:59:45 +0200 Subject: [PATCH 04/14] ci --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dee50633..b5b5f504 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,3 +81,25 @@ jobs: path: | ${{github.workspace}}/build/DMI/dmi.wasm ${{github.workspace}}/build/EVC/evc.wasm + + compile_locales: + name: Compile locales + + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Compile + run: | + cd ${{github.workspace}}/locales + ./compile_locales.sh + + - name: Publish + uses: actions/upload-artifact@v3 + with: + name: locales + path: | + ${{github.workspace}}/locales/dmi/*.mo + ${{github.workspace}}/locales/evc/*.mo From 2ac0694d24ff87a90e5b9dc1d60373a511bd6626 Mon Sep 17 00:00:00 2001 From: milek7 Date: Fri, 4 Aug 2023 02:03:20 +0200 Subject: [PATCH 05/14] ci --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5b5f504..faa0d036 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,6 +91,10 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - name: Install gettext + run: | + sudo apt-get install -y gettext + - name: Compile run: | cd ${{github.workspace}}/locales From b78eb7ee29feb7c81a60780a62f16e762f39faec Mon Sep 17 00:00:00 2001 From: me Date: Sat, 5 Aug 2023 11:14:34 +0200 Subject: [PATCH 06/14] borderless positioning --- platform/sdl_platform.cpp | 23 +++++++++++++++++------ platform/sdl_platform.h | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/platform/sdl_platform.cpp b/platform/sdl_platform.cpp index 44e702f1..cc194613 100644 --- a/platform/sdl_platform.cpp +++ b/platform/sdl_platform.cpp @@ -40,10 +40,15 @@ void SdlPlatform::SdlPlatform::load_config() } std::string SdlPlatform::SdlPlatform::get_config(const std::string_view key) +{ + return get_config(key, ""); +} + +std::string SdlPlatform::SdlPlatform::get_config(const std::string_view key, const std::string_view default) { auto it = ini_items.find(key); if (it == ini_items.end()) - return ""; + return std::string(default); return it->second; } @@ -61,16 +66,22 @@ SdlPlatform::SdlPlatform(float virtual_w, float virtual_h, const std::vector> ini_items; void load_config(); std::string get_config(const std::string_view key); + std::string get_config(const std::string_view key, const std::string_view default); BusSocketImpl bus_socket_impl; LibcTimeImpl libc_time_impl; FstreamFileImpl fstream_file_impl; From 7490fb98b8b717a1d2af5f012e56ff0f9a38798d Mon Sep 17 00:00:00 2001 From: me Date: Sat, 5 Aug 2023 11:37:14 +0200 Subject: [PATCH 07/14] on top --- platform/sdl_platform.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/platform/sdl_platform.cpp b/platform/sdl_platform.cpp index cc194613..3dbbf69d 100644 --- a/platform/sdl_platform.cpp +++ b/platform/sdl_platform.cpp @@ -63,13 +63,14 @@ SdlPlatform::SdlPlatform(float virtual_w, float virtual_h, const std::vector Date: Sat, 5 Aug 2023 11:39:37 +0200 Subject: [PATCH 08/14] hidecursor --- platform/sdl_platform.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/sdl_platform.cpp b/platform/sdl_platform.cpp index 3dbbf69d..1fd3b245 100644 --- a/platform/sdl_platform.cpp +++ b/platform/sdl_platform.cpp @@ -71,6 +71,7 @@ SdlPlatform::SdlPlatform(float virtual_w, float virtual_h, const std::vector Date: Wed, 9 Aug 2023 10:24:02 +0200 Subject: [PATCH 09/14] Establish session to report mode change --- DMI/softkeys/softkey.cpp | 2 +- DMI/softkeys/softkey.h | 1 - DMI/state/acks.cpp | 2 +- DMI/window/input_data.cpp | 2 +- EVC/Euroradio/session.cpp | 3 ++- EVC/OR_interface/interface.cpp | 2 +- EVC/Packets/radio.cpp | 2 ++ EVC/Procedures/mode_transition.cpp | 10 +++++++++- EVC/Procedures/start.cpp | 1 + 9 files changed, 18 insertions(+), 7 deletions(-) diff --git a/DMI/softkeys/softkey.cpp b/DMI/softkeys/softkey.cpp index 91b38209..efa1aaaa 100644 --- a/DMI/softkeys/softkey.cpp +++ b/DMI/softkeys/softkey.cpp @@ -20,5 +20,5 @@ void setupSoftKeys() for (int i=2; i<7; i++) { softH[i] = SoftKey(620, 60+64*(i-2)); } - softH[7] = SoftKey(620, 413); + softH[7] = SoftKey(620, 389); } \ No newline at end of file diff --git a/DMI/softkeys/softkey.h b/DMI/softkeys/softkey.h index 3f7bfc24..2c83f2cc 100644 --- a/DMI/softkeys/softkey.h +++ b/DMI/softkeys/softkey.h @@ -22,7 +22,6 @@ class SoftKey SoftKey(float x, float y) : x(x), y(y) {} void setPressed(bool pressed) { - platform->debug_print("Soft key "+std::to_string(pressed)); input_received({pressed ? UiPlatform::InputEvent::Action::Press : UiPlatform::InputEvent::Action::Release, x, y}); } }; diff --git a/DMI/state/acks.cpp b/DMI/state/acks.cpp index cc1daaab..2a1341ea 100755 --- a/DMI/state/acks.cpp +++ b/DMI/state/acks.cpp @@ -23,7 +23,7 @@ Component c4(37, 50, nullptr); Component c1(58, 50, dispAcks); Component c5(37, 50, nullptr); Component c6(37, 50, nullptr); -Component ackButton(40, 64); +Component ackButton(40, 82); extern Component c9; extern Component textArea; bool prevAck = false; diff --git a/DMI/window/input_data.cpp b/DMI/window/input_data.cpp index a59595d1..993e5cd1 100644 --- a/DMI/window/input_data.cpp +++ b/DMI/window/input_data.cpp @@ -12,7 +12,7 @@ #include "keyboard.h" #include "platform_runtime.h" input_data::input_data(std::string label_text, bool echo) : label(label_text), show_echo(echo), data_get([this] {return getData();}), -data_set([this](std::string s){setData(s);}), more("symbols/Navigation/NA_23.bmp", softkeys ? 64 : 102, 50), enter_button("symbols/Navigation/NA_20.bmp", 40, 64, nullptr, "symbols/Navigation/NA_20.bmp") +data_set([this](std::string s){setData(s);}), more("symbols/Navigation/NA_23.bmp", softkeys ? 64 : 102, 50), enter_button("symbols/Navigation/NA_20.bmp", 40, 82, nullptr, "symbols/Navigation/NA_20.bmp") { holdcursor = {0}; if(label!="") diff --git a/EVC/Euroradio/session.cpp b/EVC/Euroradio/session.cpp index f64d2dff..c04ab0e3 100644 --- a/EVC/Euroradio/session.cpp +++ b/EVC/Euroradio/session.cpp @@ -447,6 +447,7 @@ void load_contact_info() void set_rbc_contact(contact_info contact) { rbc_contact = contact; + rbc_contact_valid = true; json j; j["NID_C"] = rbc_contact->country; j["NID_RBC"] = rbc_contact->id; @@ -461,7 +462,7 @@ void set_supervising_rbc(contact_info info) handing_over_rbc = accepting_rbc = nullptr; handover_report_accepting = handover_report_max = handover_report_min = false; if (info.phone_number == NID_RADIO_t::UseShortNumber) { - info.phone_number = 5015; + info.phone_number = 139637976798103; } if (info.id == NID_RBC_t::ContactLastRBC) { if (rbc_contact) diff --git a/EVC/OR_interface/interface.cpp b/EVC/OR_interface/interface.cpp index c5324740..32d2b477 100644 --- a/EVC/OR_interface/interface.cpp +++ b/EVC/OR_interface/interface.cpp @@ -63,7 +63,7 @@ void SetParameters() { V_est = V_ura = 0; } - if (prev != 0 && V_est == 0) + if (prev != 0 && V_est == 0 && (mode == Mode::FS || mode == Mode::LS || mode == Mode::OS || mode == Mode::SR || mode == Mode::RV)) position_report_reasons[0] = true; }; manager.AddParameter(p); diff --git a/EVC/Packets/radio.cpp b/EVC/Packets/radio.cpp index 49da1a03..f356bb74 100644 --- a/EVC/Packets/radio.cpp +++ b/EVC/Packets/radio.cpp @@ -225,6 +225,8 @@ void send_position_report(bool som) if (rbcs.empty()) return; for (auto *session : rbcs) { + if (session->status != session_status::Established) + continue; auto *rep = new position_report(); fill_message(rep); auto msg = std::shared_ptr(rep); diff --git a/EVC/Procedures/mode_transition.cpp b/EVC/Procedures/mode_transition.cpp index d91e6ca6..43159c6a 100644 --- a/EVC/Procedures/mode_transition.cpp +++ b/EVC/Procedures/mode_transition.cpp @@ -364,7 +364,15 @@ void update_mode_status() for (int i=0; istatus == session_status::Inactive) && rbc_contact_valid) { + set_supervising_rbc(*rbc_contact); + if (supervising_rbc) + supervising_rbc->open(N_tries_radio); + } + position_report_reasons[1] = true; + } calculate_SvL(); } } diff --git a/EVC/Procedures/start.cpp b/EVC/Procedures/start.cpp index b1224773..8bc2b388 100644 --- a/EVC/Procedures/start.cpp +++ b/EVC/Procedures/start.cpp @@ -156,6 +156,7 @@ void update_SoM() } break; case A35: + position_valid = true; som_status = S10; break; case A23: From 81adceb2d2b7ab02ad679fb4c81a5a9905f3a6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Benito=20Lamata?= Date: Thu, 10 Aug 2023 17:00:22 +0200 Subject: [PATCH 10/14] Use DNS according to subset 037 --- EVC/CMakeLists.txt | 2 +- EVC/Euroradio/safe_radio.h | 13 +- EVC/Euroradio/tcp_safe_connection.cpp | 136 ++++++++++++++++++ ...form_terminals.h => tcp_safe_connection.h} | 18 +-- EVC/Euroradio/terminal.cpp | 94 ------------ EVC/Procedures/mode_transition.cpp | 6 +- gradle.properties | 2 +- platform/bus_tcp_bridge.cpp | 7 +- platform/console_platform.cpp | 3 +- platform/tcp_socket.cpp | 3 +- 10 files changed, 168 insertions(+), 116 deletions(-) create mode 100644 EVC/Euroradio/tcp_safe_connection.cpp rename EVC/Euroradio/{platform_terminals.h => tcp_safe_connection.h} (60%) diff --git a/EVC/CMakeLists.txt b/EVC/CMakeLists.txt index 483206cf..8eb89ac5 100644 --- a/EVC/CMakeLists.txt +++ b/EVC/CMakeLists.txt @@ -19,7 +19,7 @@ NationalFN/nationalfn.cpp NationalFN/asfa.cpp add_definitions(-DNO_THREADS) if (NOT WASM) - list(APPEND SOURCES ../platform/console_platform.cpp ../platform/console_fd_poller.cpp ../platform/tcp_socket.cpp ../platform/bus_socket_impl.cpp ../platform/tcp_listener.cpp ../platform/libc_time_impl.cpp ../platform/fstream_file_impl.cpp ../platform/bus_socket_server.cpp ../platform/bus_tcp_bridge.cpp ../libs/liborts/ip_discovery.cpp) + list(APPEND SOURCES Euroradio/tcp_safe_connection.cpp ../platform/console_platform.cpp ../platform/console_fd_poller.cpp ../platform/tcp_socket.cpp ../platform/bus_socket_impl.cpp ../platform/tcp_listener.cpp ../platform/libc_time_impl.cpp ../platform/fstream_file_impl.cpp ../platform/bus_socket_server.cpp ../platform/bus_tcp_bridge.cpp ../libs/liborts/ip_discovery.cpp) else() list(APPEND SOURCES ../platform/simrail_platform.cpp) add_definitions(-DJSON_TEST_KEEP_MACROS=1 -DJSON_HAS_FILESYSTEM=0 -DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0) diff --git a/EVC/Euroradio/safe_radio.h b/EVC/Euroradio/safe_radio.h index dc821f16..63a9ec5d 100644 --- a/EVC/Euroradio/safe_radio.h +++ b/EVC/Euroradio/safe_radio.h @@ -11,7 +11,7 @@ #include #include "../Packets/radio.h" #include "safe_radio.h" -#include "platform.h" +#include "platform_runtime.h" class communication_session; class mobile_terminal; enum struct safe_radio_status @@ -39,4 +39,15 @@ class safe_radio_connection virtual void release() = 0; void send(std::shared_ptr msg); PlatformUtil::Promise> receive(); +}; +class bus_safe_connection : public safe_radio_connection +{ + std::unique_ptr socket; + PlatformUtil::Promise rx_promise; + void data_receive(BasePlatform::BusSocket::ReceiveResult &&msg); +public: + bus_safe_connection(communication_session *session, mobile_terminal *terminal); + void update() override; + void release() override; + void send(unsigned char *data, size_t size) override; }; \ No newline at end of file diff --git a/EVC/Euroradio/tcp_safe_connection.cpp b/EVC/Euroradio/tcp_safe_connection.cpp new file mode 100644 index 00000000..c98d5a73 --- /dev/null +++ b/EVC/Euroradio/tcp_safe_connection.cpp @@ -0,0 +1,136 @@ +/* + * European Train Control System + * Copyright (C) 2019-2023 César Benito + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#include "tcp_safe_connection.h" +#include "session.h" +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#include +#include +#endif +tcp_safe_connection::tcp_safe_connection(communication_session *session, mobile_terminal *terminal, FdPoller &poller) : safe_radio_connection(session, terminal), poller(poller) +{ + std::string domain = "etcs.vtrains.dedyn.io"; + std::string hostname = "id"; + std::stringstream ss; + ss << std::setfill ('0') << std::setw(6) << std::hex << ((session->contact.country<<14) | session->contact.id); + hostname += ss.str(); + if (session->isRBC) + hostname += ".ty01"; + else + hostname += ".ty00"; + hostname += "."; + hostname += domain; + platform->debug_print("Trying RBC "+hostname); + + std::thread thr([hostname, this]() { + addrinfo hints = {}, *res = nullptr; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + getaddrinfo(hostname.c_str(), "30998", &hints, &res); + std::unique_lock lck(mtx); + if (res == nullptr) { + dns_query = "failed"; + return; + } + char buff[INET_ADDRSTRLEN]; + const char *ip = inet_ntop(AF_INET, &((const sockaddr_in *)res->ai_addr)->sin_addr, buff, INET_ADDRSTRLEN); + if (ip == nullptr) + dns_query = "failed"; + else + dns_query = std::string(ip); + freeaddrinfo(res); + }); + thr.detach(); +} + +void tcp_safe_connection::send(unsigned char *data, size_t size) +{ + socket->send(std::string((char*)data, size)); +} + +void tcp_safe_connection::data_receive(std::string &&data) +{ + rx_promise = socket->receive().then(std::bind(&tcp_safe_connection::data_receive, this, std::placeholders::_1)); + safe_radio_connection::data_receive(std::move(data)); +} + +void tcp_safe_connection::release() +{ + socket = nullptr; + rx_promise = {}; + status = safe_radio_status::Disconnected; +} + +void tcp_safe_connection::update() +{ + safe_radio_connection::update(); + std::unique_lock lck(mtx); + if (setting_up && socket == nullptr && (dns_query != "" || get_milliseconds() - connect_time > 5000)) { + std::string ip; + int port; + if (dns_query != "" && dns_query != "failed") { + ip = dns_query; + port = 30998; + } else { + for (int i=3; i>=0; i--) + { + ip += std::to_string((active_session->contact.phone_number>>(i*8+16)) & 255); + if (i>0) ip += "."; + } + port = active_session->contact.phone_number & 65535; + } + platform->debug_print("Connecting to RBC at "+ip+":"+std::to_string(port)); + int sock = ::socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + status = safe_radio_status::Failed; + return; + } +#ifdef _WIN32 + char t; +#else + int t; +#endif + t = 1; + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &t, sizeof(t)); + t = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &t, sizeof(t)); + #ifndef _WIN32 + t = 3; + setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &t, sizeof(t)); + t = 12; + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &t, sizeof(t)); + t = 3; + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &t, sizeof(t)); + t = 20000; + setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &t, sizeof(t)); + t = 1416; + setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &t, sizeof(t)); + #endif + socket = std::make_unique(sock, poller); + socket->connect(ip, port); + rx_promise = socket->receive().then(std::bind(&tcp_safe_connection::data_receive, this, std::placeholders::_1)); + } + if ((setting_up && get_milliseconds() - connect_time > 40000) || (socket != nullptr && socket->is_failed())) { + socket = nullptr; + rx_promise = {}; + status = safe_radio_status::Failed; + } + if (status == safe_radio_status::Disconnected && socket && socket->is_connected()) { + status = safe_radio_status::Connected; + setting_up = false; + } +} \ No newline at end of file diff --git a/EVC/Euroradio/platform_terminals.h b/EVC/Euroradio/tcp_safe_connection.h similarity index 60% rename from EVC/Euroradio/platform_terminals.h rename to EVC/Euroradio/tcp_safe_connection.h index 10182e4a..ba1e8a7f 100644 --- a/EVC/Euroradio/platform_terminals.h +++ b/EVC/Euroradio/tcp_safe_connection.h @@ -6,23 +6,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "terminal.h" +#pragma once +#include "safe_radio.h" #include "tcp_socket.h" -class bus_safe_connection : public safe_radio_connection -{ - std::unique_ptr socket; - PlatformUtil::Promise rx_promise; - void data_receive(BasePlatform::BusSocket::ReceiveResult &&msg); -public: - bus_safe_connection(communication_session *session, mobile_terminal *terminal); - void update() override; - void release() override; - void send(unsigned char *data, size_t size) override; -}; +#include class tcp_safe_connection : public safe_radio_connection { + std::mutex mtx; + std::string dns_query; std::unique_ptr socket; PlatformUtil::Promise rx_promise; + FdPoller &poller; void data_receive(std::string &&msg); public: tcp_safe_connection(communication_session *session, mobile_terminal *terminal, FdPoller &poller); diff --git a/EVC/Euroradio/terminal.cpp b/EVC/Euroradio/terminal.cpp index f8047f40..d5c9820e 100644 --- a/EVC/Euroradio/terminal.cpp +++ b/EVC/Euroradio/terminal.cpp @@ -10,7 +10,6 @@ #include "session.h" #include "../Version/translate.h" #include "platform_runtime.h" -#include "platform_terminals.h" mobile_terminal *mobile_terminals[2] = {new mobile_terminal(), new mobile_terminal()}; optional> AllowedRadioNetworks; @@ -120,99 +119,6 @@ void bus_safe_connection::release() rx_promise = {}; status = safe_radio_status::Disconnected; } -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#include -#endif -tcp_safe_connection::tcp_safe_connection(communication_session *session, mobile_terminal *terminal, FdPoller &poller) : safe_radio_connection(session, terminal) -{ - setting_up = true; - std::string hostname = ""; - for (int i=3; i>=0; i--) - { - hostname += std::to_string((session->contact.phone_number>>(i*8+16)) & 255); - if (i>0) hostname += "."; - } - int port = session->contact.phone_number & 65535; - /*std::string hostname = "id"; - std::stringstream ss; - ss << std::setfill ('0') << std::setw(6) << std::hex << ((session->contact.country<<14) | session->contact.id); - hostname += ss.str(); - if (session->isRBC) - hostname += ".ty01"; - else - hostname += ".ty00"; - hostname += ".etcs"; - int port = 30998;*/ - platform->debug_print("Connecting to RBC at "+hostname+":"+std::to_string(port)); - int sock = ::socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - status = safe_radio_status::Failed; - return; - } -#ifdef _WIN32 - char t; -#else - int t; -#endif - t = 1; - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &t, sizeof(t)); - t = 1; - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &t, sizeof(t)); - #ifndef _WIN32 - t = 3; - setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &t, sizeof(t)); - t = 12; - setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &t, sizeof(t)); - t = 3; - setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &t, sizeof(t)); - t = 20000; - setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &t, sizeof(t)); - t = 1416; - setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &t, sizeof(t)); - #endif - socket = std::make_unique(sock, poller); - socket->connect(hostname, port); - rx_promise = socket->receive().then(std::bind(&tcp_safe_connection::data_receive, this, std::placeholders::_1)); -} - -void tcp_safe_connection::send(unsigned char *data, size_t size) -{ - socket->send(std::string((char*)data, size)); -} - -void tcp_safe_connection::data_receive(std::string &&data) -{ - rx_promise = socket->receive().then(std::bind(&tcp_safe_connection::data_receive, this, std::placeholders::_1)); - safe_radio_connection::data_receive(std::move(data)); -} - -void tcp_safe_connection::release() -{ - socket = nullptr; - rx_promise = {}; - status = safe_radio_status::Disconnected; -} - -void tcp_safe_connection::update() -{ - safe_radio_connection::update(); - if (!socket || (setting_up && get_milliseconds() - connect_time > 40000) || socket->is_failed()) { - socket = nullptr; - rx_promise = {}; - status = safe_radio_status::Failed; - } - if (status == safe_radio_status::Disconnected && socket && socket->is_connected()) { - status = safe_radio_status::Connected; - setting_up = false; - } -} mobile_terminal::mobile_terminal() { diff --git a/EVC/Procedures/mode_transition.cpp b/EVC/Procedures/mode_transition.cpp index 43159c6a..052acad6 100644 --- a/EVC/Procedures/mode_transition.cpp +++ b/EVC/Procedures/mode_transition.cpp @@ -293,9 +293,6 @@ void update_mode_status() Mode prevmode = mode; mode = transition; last_mode_change = get_milliseconds(); - if (prevmode == Mode::NP) { - initialize_cold_movement(); - } if (mode == Mode::TR || mode == Mode::LS || mode == Mode::OS || mode == Mode::SH) overrideProcedure = false; if (mode == Mode::SR) { @@ -374,6 +371,9 @@ void update_mode_status() position_report_reasons[1] = true; } calculate_SvL(); + if (prevmode == Mode::NP) { + initialize_cold_movement(); + } } } void set_mode_deleted_data() diff --git a/gradle.properties b/gradle.properties index f6720ae0..fd2aae5b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. android.defaults.buildfeatures.buildconfig=true -android.enableJetifier=true +android.enableJetifier=false android.nonFinalResIds=false android.nonTransitiveRClass=false android.useAndroidX=true diff --git a/platform/bus_tcp_bridge.cpp b/platform/bus_tcp_bridge.cpp index d83e7e6f..03e547af 100644 --- a/platform/bus_tcp_bridge.cpp +++ b/platform/bus_tcp_bridge.cpp @@ -129,8 +129,11 @@ BusTcpBridgeManager::BusTcpBridgeManager(const std::string_view load_path, FdPol std::unique_ptr bus_socket = impl.open_bus_socket(busname, rxt); if (!bus_socket) continue; - if (busname == "evc_sim") - tcphost = ORserver::discover_server_ip(); + if (busname == "evc_sim") { + std::string disc = ORserver::discover_server_ip(); + if (disc != "") + tcphost = disc; + } auto sock = std::make_unique(tcphost, std::stoi(tcpport), fd); client_bridges.push_back(std::make_unique(std::move(bus_socket), std::move(sock), txt, newline_framing)); } else { diff --git a/platform/console_platform.cpp b/platform/console_platform.cpp index 81d1f56f..9d35acfc 100644 --- a/platform/console_platform.cpp +++ b/platform/console_platform.cpp @@ -15,7 +15,8 @@ #include #endif #ifdef EVC -#include "../EVC/Euroradio/platform_terminals.h" +#include "../EVC/Euroradio/terminal.h" +#include "../EVC/Euroradio/tcp_safe_connection.h" #endif static std::atomic* quit_request_ptr; diff --git a/platform/tcp_socket.cpp b/platform/tcp_socket.cpp index afdba524..6a9b2ec4 100644 --- a/platform/tcp_socket.cpp +++ b/platform/tcp_socket.cpp @@ -104,7 +104,8 @@ void TcpSocket::create_and_connect(const std::string_view hostname, int port) { hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo(std::string(hostname).c_str(), std::to_string(port).c_str(), &hints, &res); - + if (res == nullptr) + return; peer_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); mark_nonblocking(peer_fd); connect_promise = poller->on_fd_ready(peer_fd, POLLOUT).then([this](int rev) { From f952726e28a710bb0a04755a4a762c0b9f509b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Benito=20Lamata?= Date: Fri, 11 Aug 2023 22:06:48 +0200 Subject: [PATCH 11/14] Add DNS query for RBC address following subset 037 --- .gitmodules | 3 + CMakeLists.txt | 18 +++- EVC/CMakeLists.txt | 14 ++- EVC/Euroradio/session.cpp | 3 +- EVC/Euroradio/tcp_safe_connection.cpp | 142 ++++++++++++++++---------- EVC/Euroradio/tcp_safe_connection.h | 6 +- EVC/Euroradio/terminal.cpp | 7 +- libs/c-ares | 1 + platform/ares_dns.h | 96 +++++++++++++++++ platform/console_platform.cpp | 18 +++- platform/console_platform.h | 5 + platform/dns.h | 30 ++++++ 12 files changed, 275 insertions(+), 68 deletions(-) create mode 160000 libs/c-ares create mode 100644 platform/ares_dns.h create mode 100644 platform/dns.h diff --git a/.gitmodules b/.gitmodules index 7e2ab279..bc253290 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "libs/liborts"] path = libs/liborts url = https://github.com/cesarBLG/liborts +[submodule "libs/c-ares"] + path = libs/c-ares + url = https://github.com/c-ares/c-ares/ diff --git a/CMakeLists.txt b/CMakeLists.txt index c1a4a4b9..97ca9871 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,19 +3,31 @@ project (ETCS) set(CMAKE_CXX_STANDARD 17) option(SIMRAIL "SimRail" OFF) if (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "wasm.*") + set (WASM FALSE) +else() + set (WASM TRUE) +endif() +set(RADIO_TCP OFF) +if (NOT WASM) + if (NOT SIMRAIL) + set (RADIO_TCP ON) + endif() option(ETCS_VENDORED "Use vendored libraries" ON) if (ETCS_VENDORED) set(SDL2TTF_VENDORED ON CACHE BOOL "Vendored TTF libs") add_subdirectory(libs/SDL EXCLUDE_FROM_ALL) add_subdirectory(libs/SDL_ttf EXCLUDE_FROM_ALL) add_subdirectory(libs/liborts EXCLUDE_FROM_ALL) + if (RADIO_TCP) + add_subdirectory(libs/c-ares EXCLUDE_FROM_ALL) + endif() endif() - set (WASM FALSE) -else() - set (WASM TRUE) endif() if (SIMRAIL) add_definitions(-DSIMRAIL) endif() +if (RADIO_TCP) + add_definitions(-DRADIO_TCP) +endif() add_subdirectory(EVC) add_subdirectory(DMI) diff --git a/EVC/CMakeLists.txt b/EVC/CMakeLists.txt index 8eb89ac5..91b411ab 100644 --- a/EVC/CMakeLists.txt +++ b/EVC/CMakeLists.txt @@ -18,8 +18,12 @@ NationalFN/nationalfn.cpp NationalFN/asfa.cpp add_definitions(-DNO_THREADS) +if (RADIO_TCP) + list (APPEND SOURCES Euroradio/tcp_safe_connection.cpp) +endif() + if (NOT WASM) - list(APPEND SOURCES Euroradio/tcp_safe_connection.cpp ../platform/console_platform.cpp ../platform/console_fd_poller.cpp ../platform/tcp_socket.cpp ../platform/bus_socket_impl.cpp ../platform/tcp_listener.cpp ../platform/libc_time_impl.cpp ../platform/fstream_file_impl.cpp ../platform/bus_socket_server.cpp ../platform/bus_tcp_bridge.cpp ../libs/liborts/ip_discovery.cpp) + list(APPEND SOURCES ../platform/console_platform.cpp ../platform/console_fd_poller.cpp ../platform/tcp_socket.cpp ../platform/bus_socket_impl.cpp ../platform/tcp_listener.cpp ../platform/libc_time_impl.cpp ../platform/fstream_file_impl.cpp ../platform/bus_socket_server.cpp ../platform/bus_tcp_bridge.cpp ../libs/liborts/ip_discovery.cpp) else() list(APPEND SOURCES ../platform/simrail_platform.cpp) add_definitions(-DJSON_TEST_KEEP_MACROS=1 -DJSON_HAS_FILESYSTEM=0 -DJSON_HAS_EXPERIMENTAL_FILESYSTEM=0) @@ -48,6 +52,14 @@ target_include_directories(evc PRIVATE ../libs/liborts/include) add_definitions(-DEVC) +if (RADIO_TCP) + if (ETCS_VENDORED) + target_link_libraries(evc PRIVATE c-ares) + else() + target_link_libraries(evc PRIVATE cares) + endif() +endif() + if(WIN32) target_link_libraries(evc PRIVATE imagehlp ws2_32 psapi) endif() diff --git a/EVC/Euroradio/session.cpp b/EVC/Euroradio/session.cpp index c04ab0e3..419a3c88 100644 --- a/EVC/Euroradio/session.cpp +++ b/EVC/Euroradio/session.cpp @@ -462,7 +462,8 @@ void set_supervising_rbc(contact_info info) handing_over_rbc = accepting_rbc = nullptr; handover_report_accepting = handover_report_max = handover_report_min = false; if (info.phone_number == NID_RADIO_t::UseShortNumber) { - info.phone_number = 139637976798103; + info.country = 0; + info.id = 0; } if (info.id == NID_RBC_t::ContactLastRBC) { if (rbc_contact) diff --git a/EVC/Euroradio/tcp_safe_connection.cpp b/EVC/Euroradio/tcp_safe_connection.cpp index c98d5a73..4f85795d 100644 --- a/EVC/Euroradio/tcp_safe_connection.cpp +++ b/EVC/Euroradio/tcp_safe_connection.cpp @@ -7,8 +7,8 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "tcp_safe_connection.h" +#include "console_platform.h" #include "session.h" -#include #include #include #ifdef _WIN32 @@ -36,25 +36,14 @@ tcp_safe_connection::tcp_safe_connection(communication_session *session, mobile_ hostname += domain; platform->debug_print("Trying RBC "+hostname); - std::thread thr([hostname, this]() { - addrinfo hints = {}, *res = nullptr; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - getaddrinfo(hostname.c_str(), "30998", &hints, &res); - std::unique_lock lck(mtx); - if (res == nullptr) { - dns_query = "failed"; - return; - } - char buff[INET_ADDRSTRLEN]; - const char *ip = inet_ntop(AF_INET, &((const sockaddr_in *)res->ai_addr)->sin_addr, buff, INET_ADDRSTRLEN); - if (ip == nullptr) - dns_query = "failed"; - else - dns_query = std::string(ip); - freeaddrinfo(res); - }); - thr.detach(); + if (session->contact.phone_number == 0xFFFFFFFFFFFFFFFFUL) { + connect({"", ""}); + } else { + dns_query = static_cast(platform.get())->query_dns(hostname); + dns_query->promise.then([this](dns_entry &&e){ + connect(std::move(e)); + }); + } } void tcp_safe_connection::send(unsigned char *data, size_t size) @@ -72,18 +61,43 @@ void tcp_safe_connection::release() { socket = nullptr; rx_promise = {}; + dns_query = {}; status = safe_radio_status::Disconnected; } -void tcp_safe_connection::update() +void tcp_safe_connection::connect(dns_entry &&dns) { - safe_radio_connection::update(); - std::unique_lock lck(mtx); - if (setting_up && socket == nullptr && (dns_query != "" || get_milliseconds() - connect_time > 5000)) { - std::string ip; - int port; - if (dns_query != "" && dns_query != "failed") { - ip = dns_query; + dns_query = {}; + std::string ip; + int port; + std::map config; + { + std::vector params; + std::string s = dns.txt; + for (;;) { + size_t pos = s.find_first_of(';'); + if (pos == std::string::npos) { + if (!s.empty()) + params.push_back(s); + break; + } + params.push_back(s.substr(0,pos)); + s = s.substr(pos+1); + } + for (std::string &p : params) { + size_t pos = p.find('='); + if (pos != std::string::npos) + config[p.substr(0, pos)] = p.substr(pos+1); + } + } + if (dns.a != "" && config["txm"] != "CS") { + ip = dns.a; + port = 30998; + } else { + // CSD GSM-R call + // Use TCP anyway, but derive address from phone number + if (active_session->contact.phone_number == 0xFFFFFFFFFFFFFFFFULL) { + ip = "127.0.0.1"; port = 30998; } else { for (int i=3; i>=0; i--) @@ -93,40 +107,58 @@ void tcp_safe_connection::update() } port = active_session->contact.phone_number & 65535; } - platform->debug_print("Connecting to RBC at "+ip+":"+std::to_string(port)); - int sock = ::socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - status = safe_radio_status::Failed; - return; - } + } + platform->debug_print("Connecting to RBC at "+ip+":"+std::to_string(port)); + platform->debug_print("Connection parameters: "+dns.txt); + int sock = ::socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + status = safe_radio_status::Failed; + return; + } + #ifdef _WIN32 - char t; + char t; #else - int t; + int t; #endif - t = 1; - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &t, sizeof(t)); - t = 1; - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &t, sizeof(t)); - #ifndef _WIN32 - t = 3; - setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &t, sizeof(t)); - t = 12; - setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &t, sizeof(t)); - t = 3; - setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &t, sizeof(t)); - t = 20000; - setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &t, sizeof(t)); - t = 1416; - setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &t, sizeof(t)); - #endif - socket = std::make_unique(sock, poller); - socket->connect(ip, port); - rx_promise = socket->receive().then(std::bind(&tcp_safe_connection::data_receive, this, std::placeholders::_1)); + t = 1; + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &t, sizeof(t)); + t = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &t, sizeof(t)); + #ifndef _WIN32 + int tp[5] = {12, 3, 3, 20000, 1416}; + { + std::string tp_str = config["tp"]; + for (int i=0; i<5; i++) { + size_t pos = tp_str.find_first_of(','); + std::string sub = tp_str.substr(0,pos); + if (!sub.empty()) + tp[i] = stoi(sub); + if (pos == std::string::npos) + break; + tp_str = tp_str.substr(pos+1); + } } + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &tp[0], sizeof(tp[0])); + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &tp[1], sizeof(tp[1])); + setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &tp[2], sizeof(tp[2])); + setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &tp[3], sizeof(tp[3])); + setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tp[4], sizeof(tp[4])); + #endif + socket = std::make_unique(sock, poller); + socket->connect(ip, port); + rx_promise = socket->receive().then(std::bind(&tcp_safe_connection::data_receive, this, std::placeholders::_1)); +} + +void tcp_safe_connection::update() +{ + safe_radio_connection::update(); + if (setting_up && socket == nullptr && get_milliseconds() - connect_time > 5000) + connect({"",""}); if ((setting_up && get_milliseconds() - connect_time > 40000) || (socket != nullptr && socket->is_failed())) { socket = nullptr; rx_promise = {}; + dns_query = {}; status = safe_radio_status::Failed; } if (status == safe_radio_status::Disconnected && socket && socket->is_connected()) { diff --git a/EVC/Euroradio/tcp_safe_connection.h b/EVC/Euroradio/tcp_safe_connection.h index ba1e8a7f..1b33bb4b 100644 --- a/EVC/Euroradio/tcp_safe_connection.h +++ b/EVC/Euroradio/tcp_safe_connection.h @@ -9,15 +9,15 @@ #pragma once #include "safe_radio.h" #include "tcp_socket.h" -#include +#include "dns.h" class tcp_safe_connection : public safe_radio_connection { - std::mutex mtx; - std::string dns_query; + std::unique_ptr dns_query; std::unique_ptr socket; PlatformUtil::Promise rx_promise; FdPoller &poller; void data_receive(std::string &&msg); + void connect(dns_entry &&e); public: tcp_safe_connection(communication_session *session, mobile_terminal *terminal, FdPoller &poller); void update() override; diff --git a/EVC/Euroradio/terminal.cpp b/EVC/Euroradio/terminal.cpp index d5c9820e..0dd9792b 100644 --- a/EVC/Euroradio/terminal.cpp +++ b/EVC/Euroradio/terminal.cpp @@ -69,7 +69,12 @@ void safe_radio_connection::update() bus_safe_connection::bus_safe_connection(communication_session *session, mobile_terminal *terminal) : safe_radio_connection(session, terminal) { - socket = platform->open_socket("rbc_" + std::to_string(session->contact.phone_number), BasePlatform::BusSocket::PeerId::fourcc("EVC")); + std::string rbc = "rbc_"; + if (session->contact.phone_number == 0xFFFFFFFFFFFFFFFFULL) + rbc += "5015"; + else + rbc += std::to_string(session->contact.phone_number); + socket = platform->open_socket(rbc, BasePlatform::BusSocket::PeerId::fourcc("EVC")); if (socket) { rx_promise = socket->receive().then(std::bind(&bus_safe_connection::data_receive, this, std::placeholders::_1)); } else { diff --git a/libs/c-ares b/libs/c-ares new file mode 160000 index 00000000..bad62225 --- /dev/null +++ b/libs/c-ares @@ -0,0 +1 @@ +Subproject commit bad62225b7f6b278b92e8e85a255600b629ef517 diff --git a/platform/ares_dns.h b/platform/ares_dns.h new file mode 100644 index 00000000..353ab598 --- /dev/null +++ b/platform/ares_dns.h @@ -0,0 +1,96 @@ +/* + * European Train Control System + * Copyright (C) 2019-2023 César Benito + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once +#include "dns.h" +#include +#ifndef _WIN32 +#include "console_fd_poller.h" +#include +#include +#include +#include +#include +#else +#include +#include +#endif +class AresQuery : public DNSQuery +{ + FdPoller &poller; + ares_channel channel; + PlatformUtil::Promise timeout; + std::map> promises; + std::optional a; + std::optional txt; + static void callback_a(void *arg, int status, int timeouts, struct hostent *host) + { + AresQuery *q = (AresQuery*)arg; + if (status == ARES_SUCCESS && host->h_length > 0) { + char ip[INET_ADDRSTRLEN]; + ares_inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, INET_ADDRSTRLEN); + q->a = ip; + } else { + q->a = ""; + } + if (q->a && q->txt) { + q->fulfiller.fulfill({*q->a, *q->txt}); + } + } + static void callback_txt(void *arg, int status, int timeouts, unsigned char *buff, int alen) + { + AresQuery *q = (AresQuery*)arg; + q->txt = ""; + if (status == ARES_SUCCESS) { + ares_txt_reply *reply; + if (ares_parse_txt_reply(buff, alen, &reply) == ARES_SUCCESS) { + q->txt = std::string((char*)reply->txt, reply->length); + ares_free_data(reply); + } + } + if (q->a && q->txt) { + q->fulfiller.fulfill({*q->a, *q->txt}); + } + } +public: + AresQuery(FdPoller &poller, std::string hostname) : DNSQuery(hostname), poller(poller) + { + ares_init(&channel); + ares_gethostbyname(channel, hostname.c_str(), AF_INET, callback_a, this); + ares_query(channel, hostname.c_str(), 1, 16, callback_txt, this); + process(); + } + ~AresQuery() + { + ares_destroy(channel); + } +protected: + void process() + { + promises.clear(); + ares_socket_t fds[ARES_GETSOCK_MAXNUM]; + int flags = ares_getsock(channel, fds, ARES_GETSOCK_MAXNUM); + for (int i=0; idelay(tv.tv_sec*1000 + tv.tv_usec/1000).then([this](){process();}); + } +}; \ No newline at end of file diff --git a/platform/console_platform.cpp b/platform/console_platform.cpp index 9d35acfc..fe7138d5 100644 --- a/platform/console_platform.cpp +++ b/platform/console_platform.cpp @@ -14,9 +14,10 @@ #ifdef __ANDROID__ #include #endif -#ifdef EVC +#ifdef RADIO_TCP #include "../EVC/Euroradio/terminal.h" #include "../EVC/Euroradio/tcp_safe_connection.h" +#include "ares_dns.h" #endif static std::atomic* quit_request_ptr; @@ -67,8 +68,8 @@ ConsolePlatform::ConsolePlatform(const std::string_view path, const std::vector< signal(SIGTERM, &sigterm_handler); signal(SIGINT, &sigterm_handler); #endif -#ifdef EVC -#if !SIMRAIL +#if RADIO_TCP + ares_library_init(ARES_LIB_INIT_ALL); for (auto *t : mobile_terminals) { t->setup_connection = [t, this](communication_session *session) { if (!t->registered || t->radio_network_id != RadioNetworkId) @@ -78,11 +79,17 @@ ConsolePlatform::ConsolePlatform(const std::string_view path, const std::vector< return conn; }; } -#endif #endif PlatformUtil::DeferredFulfillment::list = &event_list; } +#if RADIO_TCP +std::unique_ptr ConsolePlatform::query_dns(std::string hostname) +{ + return std::make_unique(poller, hostname); +} +#endif + ConsolePlatform::~ConsolePlatform() { on_quit_request_list.clear(); on_quit_list.clear(); @@ -94,6 +101,9 @@ ConsolePlatform::~ConsolePlatform() { signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); #endif +#if RADIO_TCP + ares_library_cleanup(); +#endif } int64_t ConsolePlatform::get_timer() { diff --git a/platform/console_platform.h b/platform/console_platform.h index bd5269b5..2d3a36ff 100644 --- a/platform/console_platform.h +++ b/platform/console_platform.h @@ -18,6 +18,7 @@ #include "bus_socket_server.h" #include "bus_tcp_bridge.h" #include "console_fd_poller.h" +#include "dns.h" class ConsolePlatform final : public BasePlatform { private: @@ -59,5 +60,9 @@ class ConsolePlatform final : public BasePlatform { PlatformUtil::Promise on_quit_request() override; PlatformUtil::Promise on_quit() override; +#if RADIO_TCP + std::unique_ptr query_dns(std::string hostname); +#endif + void quit() override; }; diff --git a/platform/dns.h b/platform/dns.h new file mode 100644 index 00000000..71a3279c --- /dev/null +++ b/platform/dns.h @@ -0,0 +1,30 @@ +/* + * European Train Control System + * Copyright (C) 2019-2023 César Benito + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once +#include "platform_runtime.h" +struct dns_entry +{ + std::string a; + std::string txt; +}; +class DNSQuery +{ +protected: + std::string hostname; + PlatformUtil::Fulfiller fulfiller; +public: + PlatformUtil::Promise promise; + DNSQuery(std::string hostname) : hostname(hostname) + { + auto pair = PlatformUtil::PromiseFactory::create(); + promise = std::move(pair.first); + fulfiller = std::move(pair.second); + } + virtual ~DNSQuery() {} +}; \ No newline at end of file From 836a7a64c4f40e8ebf495c54c08fe9ff97928cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Benito=20Lamata?= Date: Sat, 12 Aug 2023 13:09:36 +0200 Subject: [PATCH 12/14] Refactor builds --- CMakeLists.txt | 3 +++ EVC/CMakeLists.txt | 3 ++- EVC/Euroradio/tcp_safe_connection.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97ca9871..9de03cd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,5 +29,8 @@ endif() if (RADIO_TCP) add_definitions(-DRADIO_TCP) endif() +if (WIN32) + add_definitions(-D_WIN32_WINNT=0x602) +endif() add_subdirectory(EVC) add_subdirectory(DMI) diff --git a/EVC/CMakeLists.txt b/EVC/CMakeLists.txt index 91b411ab..9238a4ed 100644 --- a/EVC/CMakeLists.txt +++ b/EVC/CMakeLists.txt @@ -56,7 +56,8 @@ if (RADIO_TCP) if (ETCS_VENDORED) target_link_libraries(evc PRIVATE c-ares) else() - target_link_libraries(evc PRIVATE cares) + find_package(c-ares REQUIRED CONFIG REQUIRED COMPONENTS c-ares) + target_link_libraries(evc PRIVATE ${c-ares_LIBRARY}) endif() endif() diff --git a/EVC/Euroradio/tcp_safe_connection.cpp b/EVC/Euroradio/tcp_safe_connection.cpp index 4f85795d..5d98007d 100644 --- a/EVC/Euroradio/tcp_safe_connection.cpp +++ b/EVC/Euroradio/tcp_safe_connection.cpp @@ -92,7 +92,7 @@ void tcp_safe_connection::connect(dns_entry &&dns) } if (dns.a != "" && config["txm"] != "CS") { ip = dns.a; - port = 30998; + port = config.find("port") != config.end() ? stoi(config["port"]) : 30998; } else { // CSD GSM-R call // Use TCP anyway, but derive address from phone number From 80f62826098cf98819fc9fe91239d0f45fa114ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Benito=20Lamata?= Date: Sat, 12 Aug 2023 16:43:39 +0200 Subject: [PATCH 13/14] BCD phone number --- EVC/DMI/windows.cpp | 6 +++--- EVC/Euroradio/session.cpp | 24 ++++++++++++++++++++++++ EVC/Euroradio/session.h | 4 +++- EVC/Euroradio/tcp_safe_connection.cpp | 10 +++++++++- EVC/Euroradio/terminal.cpp | 2 +- EVC/Packets/information.cpp | 4 ++-- EVC/Packets/messages.cpp | 2 +- EVC/Packets/variables.h | 14 -------------- 8 files changed, 43 insertions(+), 23 deletions(-) diff --git a/EVC/DMI/windows.cpp b/EVC/DMI/windows.cpp index 2900cc4f..474d1903 100644 --- a/EVC/DMI/windows.cpp +++ b/EVC/DMI/windows.cpp @@ -150,7 +150,7 @@ json rbc_data_window() json j = R"({"active":"rbc_data_window"})"_json; std::vector inputs = { build_numeric_field(get_text("RBC ID"), rbc_contact ? std::to_string(rbc_contact->country<<14 | rbc_contact->id) : ""), - build_numeric_field(get_text("RBC phone number"), rbc_contact ? std::to_string(rbc_contact->phone_number) : "") + build_numeric_field(get_text("RBC phone number"), rbc_contact ? from_bcd(rbc_contact->phone_number) : "") }; inputs[0]["Echo"] = false; inputs[1]["Echo"] = false; @@ -291,7 +291,7 @@ json data_view_window() fields.push_back(build_field(get_text("Radio network ID"), RadioNetworkId)); if (rbc_contact) { fields.push_back(build_field(get_text("RBC ID"), std::to_string(rbc_contact->id))); - fields.push_back(build_field(get_text("RBC phone number"), std::to_string(rbc_contact->phone_number))); + fields.push_back(build_field(get_text("RBC phone number"), from_bcd(rbc_contact->phone_number))); } fields.push_back(build_field("", "")); @@ -989,7 +989,7 @@ void validate_data_entry(std::string name, json &result) active_dialog_step = "S1"; } else if (name == get_text("RBC data")) { uint32_t id = atoll(result[get_text("RBC ID")].get().c_str()); - uint64_t number = atoll(result[get_text("RBC phone number")].get().c_str()); + uint64_t number = to_bcd(result[get_text("RBC phone number")].get().c_str()); set_supervising_rbc(contact_info({id>>14,id&((1<<14) - 1),number})); if (som_active && som_status == S3 ) { som_status = A31; diff --git a/EVC/Euroradio/session.cpp b/EVC/Euroradio/session.cpp index 419a3c88..ee6f1277 100644 --- a/EVC/Euroradio/session.cpp +++ b/EVC/Euroradio/session.cpp @@ -519,4 +519,28 @@ void terminate_session(contact_info info) accepting_rbc = nullptr; } } +} +std::string from_bcd(uint64_t number) +{ + std::string str; + for (int i=15; i>=0; i--) + { + int c = (number>>(4*i))&15; + if (c == 15) + continue; + if (c >= 10) + return ""; + str += (char)(c+48); + } + return str; +} +uint64_t to_bcd(std::string number) +{ + uint64_t bcd = 0; + for (int i=0; i<16; i++) { + if (i < number.size()) + bcd = (bcd<<4) | (number[i]-48); + else bcd = (bcd<<4) | 0xF; + } + return bcd; } \ No newline at end of file diff --git a/EVC/Euroradio/session.h b/EVC/Euroradio/session.h index a8f947d7..77d46711 100644 --- a/EVC/Euroradio/session.h +++ b/EVC/Euroradio/session.h @@ -80,4 +80,6 @@ void set_rbc_contact(contact_info contact); void update_euroradio(); void set_supervising_rbc(contact_info info); void terminate_session(contact_info info); -void rbc_handover(distance d, contact_info newrbc); \ No newline at end of file +void rbc_handover(distance d, contact_info newrbc); +std::string from_bcd(uint64_t number); +uint64_t to_bcd(std::string number); \ No newline at end of file diff --git a/EVC/Euroradio/tcp_safe_connection.cpp b/EVC/Euroradio/tcp_safe_connection.cpp index 5d98007d..21d8ed19 100644 --- a/EVC/Euroradio/tcp_safe_connection.cpp +++ b/EVC/Euroradio/tcp_safe_connection.cpp @@ -100,9 +100,17 @@ void tcp_safe_connection::connect(dns_entry &&dns) ip = "127.0.0.1"; port = 30998; } else { + uint64_t num=0; + for (int i=15; i>=0; i--) + { + int c = (active_session->contact.phone_number>>(4*i))&15; + if (c == 15) + continue; + num = 10*num + c; + } for (int i=3; i>=0; i--) { - ip += std::to_string((active_session->contact.phone_number>>(i*8+16)) & 255); + ip += std::to_string((num>>(i*8+16)) & 255); if (i>0) ip += "."; } port = active_session->contact.phone_number & 65535; diff --git a/EVC/Euroradio/terminal.cpp b/EVC/Euroradio/terminal.cpp index 0dd9792b..3ad834b8 100644 --- a/EVC/Euroradio/terminal.cpp +++ b/EVC/Euroradio/terminal.cpp @@ -73,7 +73,7 @@ bus_safe_connection::bus_safe_connection(communication_session *session, mobile_ if (session->contact.phone_number == 0xFFFFFFFFFFFFFFFFULL) rbc += "5015"; else - rbc += std::to_string(session->contact.phone_number); + rbc += from_bcd(session->contact.phone_number); socket = platform->open_socket(rbc, BasePlatform::BusSocket::PeerId::fourcc("EVC")); if (socket) { rx_promise = socket->receive().then(std::bind(&bus_safe_connection::data_receive, this, std::placeholders::_1)); diff --git a/EVC/Packets/information.cpp b/EVC/Packets/information.cpp index 7603999d..c8800cbb 100644 --- a/EVC/Packets/information.cpp +++ b/EVC/Packets/information.cpp @@ -189,7 +189,7 @@ void session_management_information::handle() { SessionManagement &session = *(SessionManagement*)linked_packets.front().get(); if (mode != Mode::SL || session.Q_SLEEPSESSION == Q_SLEEPSESSION_t::ExecuteOrder) { - contact_info info = {session.NID_C, session.NID_RBC, session.NID_RADIO.get_value()}; + contact_info info = {session.NID_C, session.NID_RBC, session.NID_RADIO}; if (session.Q_RBC == Q_RBC_t::EstablishSession) { set_supervising_rbc(info); if (supervising_rbc && mode != Mode::SH && mode != Mode::PS) @@ -313,7 +313,7 @@ void rbc_transition_information::handle() { RBCTransitionOrder o = *(RBCTransitionOrder*)linked_packets.front().get(); if (mode != Mode::SL || o.Q_SLEEPSESSION == Q_SLEEPSESSION_t::ExecuteOrder) { - contact_info info = {o.NID_C, o.NID_RBC, o.NID_RADIO.get_value()}; + contact_info info = {o.NID_C, o.NID_RBC, o.NID_RADIO}; rbc_handover(ref + o.D_RBCTR.get_value(o.Q_SCALE), info); } } diff --git a/EVC/Packets/messages.cpp b/EVC/Packets/messages.cpp index 2236afe6..2e1355f7 100644 --- a/EVC/Packets/messages.cpp +++ b/EVC/Packets/messages.cpp @@ -946,7 +946,7 @@ bool level_filter(std::shared_ptr info, std::listindex_level == 16) { RBCTransitionOrder o = *(RBCTransitionOrder*)m->linked_packets.front().get(); - contact_info info2 = {o.NID_C, o.NID_RBC, o.NID_RADIO.get_value()}; + contact_info info2 = {o.NID_C, o.NID_RBC, o.NID_RADIO}; if (info2 == info) return false; } diff --git a/EVC/Packets/variables.h b/EVC/Packets/variables.h index 02a0e503..c6e6b237 100644 --- a/EVC/Packets/variables.h +++ b/EVC/Packets/variables.h @@ -1230,20 +1230,6 @@ struct NID_RADIO_t : ETCS_variable_custom { static const uint64_t UseShortNumber=std::numeric_limits::max(); NID_RADIO_t() : ETCS_variable_custom(64) {} - uint64_t get_value() - { - if (rawdata == UseShortNumber) - return rawdata; - uint64_t value=0; - for (int i=15; i>=0; i--) - { - int c = (rawdata>>(4*i))&15; - if (c == 15) - continue; - value = 10*value + c; - } - return value; - } }; struct NID_RBC_t : ETCS_variable { From 225a0d629fdb26658920f4045bfc38aff6c60c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Benito=20Lamata?= Date: Sat, 19 Aug 2023 14:14:00 +0200 Subject: [PATCH 14/14] Fix OR interface --- EVC/OR_interface/interface.cpp | 6 +++++- EVC/OR_interface/interface.h | 2 +- EVC/evc.cpp | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/EVC/OR_interface/interface.cpp b/EVC/OR_interface/interface.cpp index 32d2b477..56d13a19 100644 --- a/EVC/OR_interface/interface.cpp +++ b/EVC/OR_interface/interface.cpp @@ -323,7 +323,6 @@ void register_parameter(std::string param) void sim_receive(BasePlatform::BusSocket::Message &&msg) { manager.ParseLine(sim_wrapper.get(), msg.data); - std::for_each(manager.parameters.begin(), manager.parameters.end(), [](ORserver::Parameter* p){p->Send();}); } void sim_receive(BasePlatform::BusSocket::JoinNotification &&msg) @@ -375,3 +374,8 @@ void start_or_iface() register_parameter("etcs::failed"); register_parameter("serie"); } + +void update_or_iface() +{ + std::for_each(manager.parameters.begin(), manager.parameters.end(), [](ORserver::Parameter* p){p->Send();}); +} diff --git a/EVC/OR_interface/interface.h b/EVC/OR_interface/interface.h index baa0a665..ceacc534 100644 --- a/EVC/OR_interface/interface.h +++ b/EVC/OR_interface/interface.h @@ -10,4 +10,4 @@ #include #include "../Packets/radio.h" void start_or_iface(); -//extern std::list pendingmessages; \ No newline at end of file +void update_or_iface(); \ No newline at end of file diff --git a/EVC/evc.cpp b/EVC/evc.cpp index 9816092b..939fb7fb 100755 --- a/EVC/evc.cpp +++ b/EVC/evc.cpp @@ -186,6 +186,7 @@ void on_platform_ready() } void update() { + update_or_iface(); update_odometer(); update_geographical_position(); update_track_comm();