diff options
| author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-08-13 10:48:49 +0200 | 
|---|---|---|
| committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-08-13 10:48:49 +0200 | 
| commit | ef536ba0e190df286d273ded5ba93f4a2f39b45e (patch) | |
| tree | 5d45c336e2244e3e59e5ae681dd74df037d809ad /src | |
| parent | 14f69f9c915cf644147a52b803d79ff8f40a4ea1 (diff) | |
| download | dabmux-ef536ba0e190df286d273ded5ba93f4a2f39b45e.tar.gz dabmux-ef536ba0e190df286d273ded5ba93f4a2f39b45e.tar.bz2 dabmux-ef536ba0e190df286d273ded5ba93f4a2f39b45e.zip | |
Pull in files from odr-mmbtools-common
Telnet RC is now single-user only.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ClockTAI.cpp | 562 | ||||
| -rw-r--r-- | src/ClockTAI.h | 102 | ||||
| -rw-r--r-- | src/Log.cpp | 143 | ||||
| -rw-r--r-- | src/Log.h | 157 | ||||
| -rw-r--r-- | src/RemoteControl.cpp | 595 | ||||
| -rw-r--r-- | src/RemoteControl.h | 263 | ||||
| -rw-r--r-- | src/crc.c | 266 | ||||
| -rw-r--r-- | src/crc.h | 59 | 
8 files changed, 0 insertions, 2147 deletions
| diff --git a/src/ClockTAI.cpp b/src/ClockTAI.cpp deleted file mode 100644 index c376c07..0000000 --- a/src/ClockTAI.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/* -   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -   2011, 2012 Her Majesty the Queen in Right of Canada (Communications -   Research Center Canada) - -   Copyright (C) 2019 -   Matthias P. Braendli, matthias.braendli@mpb.li - -    http://www.opendigitalradio.org -   */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. -*/ - -/* This file downloads the TAI-UTC bulletins from the from IETF and parses them - * so that correct time can be communicated in EDI timestamps. - * - * This file contains self-test code that can be executed by running - *  g++ -g -Wall -DTEST -DHAVE_CURL -std=c++11 -lcurl -pthread \ - *  ClockTAI.cpp Log.cpp RemoteControl.cpp -lboost_system -o taitest && ./taitest - */ - -#ifdef HAVE_CONFIG_H -#   include "config.h" -#endif - -#include "ClockTAI.h" -#include "Log.h" - -#include <time.h> -#include <stdio.h> -#include <errno.h> -#if SUPPORT_SETTING_CLOCK_TAI -#  include <sys/timex.h> -#endif -#ifdef HAVE_CURL -#  include <curl/curl.h> -#endif -#include <array> -#include <string> -#include <iostream> -#include <algorithm> -#include <regex> - -using namespace std; - -#ifdef TEST -static bool wait_longer = true; -#endif - -constexpr int download_retry_interval_hours = 1; - -// Offset between NTP time and POSIX time: -// timestamp_unix = timestamp_ntp - ntp_unix_offset -const int64_t ntp_unix_offset = 2208988800L; - -// leap seconds insertion bulletin is available from the IETF and in the TZ -// distribution -static array<const char*, 2> default_tai_urls = { -    "https://www.ietf.org/timezones/data/leap-seconds.list", -    "https://raw.githubusercontent.com/eggert/tz/master/leap-seconds.list", -}; - -// According to the Filesystem Hierarchy Standard, the data in -// /var/tmp "must not be deleted when the system is booted." -static const char *tai_cache_location = "/var/tmp/odr-dabmux-leap-seconds.cache"; - -// read TAI offset from a valid bulletin in IETF format -static int parse_ietf_bulletin(const std::string& bulletin) -{ -    // Example Line: -    // 3692217600	37	# 1 Jan 2017 -    // -    // NTP timestamp<TAB>leap seconds<TAB># some comment -    // The NTP timestamp starts at epoch 1.1.1900. -    // The difference between NTP timestamps and unix epoch is 70 -    // years i.e. 2208988800 seconds - -    std::regex regex_bulletin(R"(([0-9]+)\s+([0-9]+)\s+#.*)"); - -    time_t now = time(nullptr); - -    int tai_utc_offset = 0; - -    int tai_utc_offset_valid = false; - -    stringstream ss(bulletin); - -    /* We cannot just take the last line, because it might -     * be in the future, announcing an upcoming leap second. -     * -     * So we need to look at the current date, and compare it -     * with the date of the leap second. -     */ -    for (string line; getline(ss, line); ) { - -        std::smatch bulletin_entry; - -        bool is_match = std::regex_search(line, bulletin_entry, regex_bulletin); -        if (is_match) { -            if (bulletin_entry.size() != 3) { -                throw runtime_error( -                        "Incorrect number of matched TAI IETF bulletin entries"); -            } -            const string bulletin_ntp_timestamp(bulletin_entry[1]); -            const string bulletin_offset(bulletin_entry[2]); - -            const int64_t timestamp_unix = -                std::atoll(bulletin_ntp_timestamp.c_str()) - ntp_unix_offset; - -            const int offset = std::atoi(bulletin_offset.c_str()); -            // Ignore entries announcing leap seconds in the future -            if (timestamp_unix < now) { -                tai_utc_offset = offset; -                tai_utc_offset_valid = true; -            } -#if TEST -            else { -                cerr << "IETF Ignoring offset " << bulletin_offset << -                    " at TS " << bulletin_ntp_timestamp << -                    " in the future" << endl; -            } -#endif -        } -    } - -    if (not tai_utc_offset_valid) { -        throw runtime_error("No data in TAI bulletin"); -    } - -    return tai_utc_offset; -} - - -struct bulletin_state { -    bool valid = false; -    int64_t expiry = 0; -    int offset = 0; - -    bool usable() const { return valid and expiry > 0; } -}; - -static bulletin_state parse_bulletin(const string& bulletin) -{ -    // The bulletin contains one line that specifies an expiration date -    // in NTP time. If that point in time is in the future, we consider -    // the bulletin valid. -    // -    // The entry looks like this: -    //#@	3707596800 - -    bulletin_state ret; - -    std::regex regex_expiration(R"(#@\s+([0-9]+))"); - -    time_t now = time(nullptr); - -    stringstream ss(bulletin); - -    for (string line; getline(ss, line); ) { -        std::smatch bulletin_entry; - -        bool is_match = std::regex_search(line, bulletin_entry, regex_expiration); -        if (is_match) { -            if (bulletin_entry.size() != 2) { -                throw runtime_error( -                        "Incorrect number of matched TAI IETF bulletin expiration"); -            } -            const string expiry_data_str(bulletin_entry[1]); -            const int64_t expiry_unix = -                std::atoll(expiry_data_str.c_str()) - ntp_unix_offset; - -#ifdef TEST -            etiLog.level(info) << "Bulletin expires in " << expiry_unix - now; -#endif -            ret.expiry = expiry_unix - now; -            try { -                ret.offset = parse_ietf_bulletin(bulletin); -                ret.valid = true; -            } -            catch (const runtime_error& e) { -                etiLog.level(warn) << "Bulletin expiry ok but parse error: " << e.what(); -            } -            break; -        } -    } -    return ret; -} - - -// callback that receives data from cURL -static size_t fill_bulletin(char *ptr, size_t size, size_t nmemb, void *ctx) -{ -    auto *bulletin = reinterpret_cast<stringstream*>(ctx); - -    size_t len = size * nmemb; -    for (size_t i = 0; i < len; i++) { -        *bulletin << ptr[i]; -    } -    return len; -} - -static string download_tai_utc_bulletin(const char* url) -{ -    stringstream bulletin; - -#ifdef HAVE_CURL -    CURL *curl; -    CURLcode res; - -    curl = curl_easy_init(); -    if (curl) { -        curl_easy_setopt(curl, CURLOPT_URL, url); -        /* Tell libcurl to follow redirection */ -        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); -        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fill_bulletin); -        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &bulletin); - -        res = curl_easy_perform(curl); -        /* always cleanup ! */ -        curl_easy_cleanup(curl); - -        if (res != CURLE_OK) { -            throw runtime_error( "TAI-UTC bulletin download failed: " + -                    string(curl_easy_strerror(res))); -        } -    } -    return bulletin.str(); -#else -    throw runtime_error("Cannot download TAI Clock information without cURL"); -#endif // HAVE_CURL -} - -static string load_bulletin_from_file(const char* cache_filename) -{ -    // Clear the bulletin -    ifstream f(cache_filename); -    if (not f.good()) { -        return {}; -    } - -    stringstream ss; -    ss << f.rdbuf(); -    f.close(); - -    return ss.str(); -} - -ClockTAI::ClockTAI(const std::vector<std::string>& bulletin_urls) : -    RemoteControllable("clocktai") -{ -    RC_ADD_PARAMETER(expiry, "Number of seconds until TAI Bulletin expires"); - -    if (bulletin_urls.empty()) { -        etiLog.level(debug) << "Initialising default TAI Bulletin URLs"; -        for (const auto url : default_tai_urls) { -            m_bulletin_urls.push_back(url); -        } -    } -    else { -        etiLog.level(debug) << "Initialising user-configured TAI Bulletin URLs"; -        m_bulletin_urls = bulletin_urls; -    } - -    for (const auto url : m_bulletin_urls) { -        etiLog.level(info) << "TAI Bulletin URL: '" << url << "'"; -    } -} - -int ClockTAI::get_valid_offset() -{ -    int offset = 0; -    bool offset_valid = false; - -    std::unique_lock<std::mutex> lock(m_data_mutex); - -    const auto state = parse_bulletin(m_bulletin); -    if (state.usable()) { -#if TEST -        etiLog.level(info) << "Bulletin already valid"; -#endif -        offset = state.offset; -        offset_valid = true; -    } -    else { -        const auto cache_bulletin = load_bulletin_from_file(tai_cache_location); -        const auto cache_state = parse_bulletin(cache_bulletin); - -        if (cache_state.usable()) { -            m_bulletin = cache_bulletin; -            offset = cache_state.offset; -            offset_valid = true; -#if TEST -            etiLog.level(info) << "Bulletin from cache valid with offset=" << offset; -#endif -        } -        else { -            for (const auto url : m_bulletin_urls) { -                try { -#if TEST -                    etiLog.level(info) << "Load bulletin from " << url; -#endif -                    const auto new_bulletin = download_tai_utc_bulletin(url.c_str()); -                    const auto new_state = parse_bulletin(new_bulletin); -                    if (new_state.usable()) { -                        m_bulletin = new_bulletin; -                        offset = new_state.offset; -                        offset_valid = true; - -                        etiLog.level(debug) << "Loaded valid TAI Bulletin from " << -                            url << " giving offset=" << offset; -                    } -                    else { -                        etiLog.level(debug) << "Skipping invalid TAI bulletin from " -                            << url; -                    } -                } -                catch (const runtime_error& e) { -                    etiLog.level(warn) << -                        "TAI-UTC offset could not be retrieved from " << -                        url << " : " << e.what(); -                } - -                if (offset_valid) { -                    update_cache(tai_cache_location); -                    break; -                } -            } -        } -    } - -    if (offset_valid) { -        // With the current evolution of the offset, we're probably going -        // to reach 500 long after DAB gets replaced by another standard. -        if (offset < 0 or offset > 500) { -            stringstream ss; -            ss << "TAI offset " << offset << " out of range"; -            throw range_error(ss.str()); -        } - -        return offset; -    } -    else { -        // Try again later -        throw download_failed(); -    } -} - - -int ClockTAI::get_offset() -{ -    using namespace std::chrono; -    const auto time_now = system_clock::now(); - -    std::unique_lock<std::mutex> lock(m_data_mutex); - -    if (not m_offset_valid) { -#ifdef TEST -        // Assume we've downloaded it in the past: - -        m_offset = 37; // Valid in early 2017 -        m_offset_valid = true; - -        // Simulate requiring a new download -        m_bulletin_download_time = time_now - hours(24 * 40); -#else -        // First time we run we must block until we know -        // the offset -        lock.unlock(); -        try { -            m_offset = get_valid_offset(); -        } -        catch (const download_failed&) { -            throw runtime_error("Unable to download TAI bulletin"); -        } -        lock.lock(); -        m_offset_valid = true; -        m_bulletin_download_time = time_now; -#endif -        etiLog.level(info) << -            "Initialised TAI-UTC offset to " << m_offset << "s."; -    } - -    if (time_now - m_bulletin_download_time > hours(24 * 31)) { -        // Refresh if it's older than one month. Leap seconds are -        // announced several months in advance -        etiLog.level(debug) << "Trying to refresh TAI bulletin"; - -        if (m_offset_future.valid()) { -            auto state = m_offset_future.wait_for(seconds(0)); -            switch (state) { -                case future_status::ready: -                    try { -                        m_offset = m_offset_future.get(); -                        m_offset_valid = true; -                        m_bulletin_download_time = time_now; - -                        etiLog.level(info) << -                            "Updated TAI-UTC offset to " << m_offset << "s."; -                    } -                    catch (const download_failed&) { -                        etiLog.level(warn) << -                            "TAI-UTC download failed, will retry in " << -                            download_retry_interval_hours << " hour(s)"; - -                        m_bulletin_download_time += hours(download_retry_interval_hours); -                    } -#ifdef TEST -                    wait_longer = false; -#endif -                    break; - -                case future_status::deferred: -                case future_status::timeout: -                    // Not ready yet -#ifdef TEST -                    etiLog.level(debug) << "  async not ready yet"; -#endif -                    break; -            } -        } -        else { -#ifdef TEST -            etiLog.level(debug) << " Launch async"; -#endif -            m_offset_future = async(launch::async, &ClockTAI::get_valid_offset, this); -        } -    } - -    return m_offset; -} - -#if SUPPORT_SETTING_CLOCK_TAI -int ClockTAI::update_local_tai_clock(int offset) -{ -    struct timex timex_request; -    timex_request.modes = ADJ_TAI; -    timex_request.constant = offset; - -    int err = adjtimex(&timex_request); -    if (err == -1) { -        perror("adjtimex"); -    } - -    printf("adjtimex: %d, tai %d\n", err, timex_request.tai); - -    return err; -} -#endif - -void ClockTAI::update_cache(const char* cache_filename) -{ -    ofstream f(cache_filename); -    if (not f.good()) { -        throw runtime_error("TAI-UTC bulletin open cache for writing"); -    } - -    f << m_bulletin; -    f.close(); -} - - -void ClockTAI::set_parameter(const string& parameter, const string& value) -{ -    if (parameter == "expiry") { -        throw ParameterError("Parameter '" + parameter + -            "' is not read-only in controllable " + get_rc_name()); -    } -    else { -        throw ParameterError("Parameter '" + parameter + -            "' is not exported by controllable " + get_rc_name()); -    } -} - -const string ClockTAI::get_parameter(const string& parameter) const -{ -    if (parameter == "expiry") { -        std::unique_lock<std::mutex> lock(m_data_mutex); -        const int64_t expiry = parse_bulletin(m_bulletin).expiry; -        if (expiry > 0) { -            return to_string(expiry); -        } -        else { -            return "Bulletin expired or invalid!"; -        } -    } -    else { -        throw ParameterError("Parameter '" + parameter + -            "' is not exported by controllable " + get_rc_name()); -    } -} - -#if 0 -// Example testing code -void debug_tai_clk() -{ -    struct timespec rt_clk; - -    int err = clock_gettime(CLOCK_REALTIME, &rt_clk); -    if (err) { -        perror("REALTIME clock_gettime failed"); -    } - -    struct timespec tai_clk; - -    err = clock_gettime(CLOCK_TAI, &tai_clk); -    if (err) { -        perror("TAI clock_gettime failed"); -    } - -    printf("RT - TAI = %ld\n", rt_clk.tv_sec - tai_clk.tv_sec); - - -    struct timex timex_request; -    timex_request.modes = 0; // Do not set anything - -    err = adjtimex(&timex_request); -    if (err == -1) { -        perror("adjtimex"); -    } - -    printf("adjtimex: %d, tai %d\n", err, timex_request.tai); -} -#endif - -#if TEST -int main(int argc, char **argv) -{ -    using namespace std; - -    ClockTAI tai({}); - -    while (wait_longer) { -        try { -            etiLog.level(info) << -                "Offset is " << tai.get_offset(); -        } -        catch (const exception &e) { -            etiLog.level(error) << -                "Exception " << e.what(); -        } - -        this_thread::sleep_for(chrono::seconds(2)); -    } - -    return 0; -} -#endif - diff --git a/src/ClockTAI.h b/src/ClockTAI.h deleted file mode 100644 index 4b3c2ff..0000000 --- a/src/ClockTAI.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -   2011, 2012 Her Majesty the Queen in Right of Canada (Communications -   Research Center Canada) - -   Copyright (C) 2019 -   Matthias P. Braendli, matthias.braendli@mpb.li - -    http://www.opendigitalradio.org -   */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. -*/ - -/* The EDI output needs TAI clock, according to ETSI TS 102 693 Annex F - * "EDI Timestamps". This module can set the local CLOCK_TAI clock by - * setting the TAI-UTC offset using adjtimex. - * - * This functionality requires Linux 3.10 (30 Jun 2013) or newer. - */ - -#pragma once - -#include <stdint.h> -#include <stdlib.h> -#include <sstream> -#include <chrono> -#include <future> -#include <mutex> -#include <string> -#include <vector> -#include "RemoteControl.h" - -// EDI needs to know UTC-TAI, but doesn't need the CLOCK_TAI to be set. -// We can keep this code, maybe for future use -#define SUPPORT_SETTING_CLOCK_TAI 0 - -/* Loads, parses and represents TAI-UTC offset information from the IETF bulletin */ -class ClockTAI : public RemoteControllable { -    public: -        ClockTAI(const std::vector<std::string>& bulletin_urls); - -        // Fetch the bulletin from the IETF website and return the current -        // TAI-UTC offset. -        // Throws runtime_error on failure. -        int get_offset(void); - -#if SUPPORT_SETTING_CLOCK_TAI -        // Update the local TAI clock according to the TAI-UTC offset -        // return 0 on success -        int update_local_tai_clock(int offset); -#endif - -    private: -        class download_failed {}; - -        // Either retrieve the bulletin from the cache or if necessarly -        // download it, and calculate the TAI-UTC offset. -        // Returns the offset or throws download_failed or a range_error -        // if the offset is out of bounds. -        int get_valid_offset(void); - -        // Download of new bulletin is done asynchronously -        std::future<int> m_offset_future; - -        // Protect all data members, as RC functions are in another thread -        mutable std::mutex m_data_mutex; - -        // The currently used TAI-UTC offset -        int m_offset = 0; -        int m_offset_valid = false; - -        std::vector<std::string> m_bulletin_urls; - -        std::string m_bulletin; -        std::chrono::system_clock::time_point m_bulletin_download_time; - -        // Update the cache file with the current m_bulletin -        void update_cache(const char* cache_filename); - - -        /* Remote control */ -        virtual void set_parameter(const std::string& parameter, -               const std::string& value); - -        /* Getting a parameter always returns a string. */ -        virtual const std::string get_parameter(const std::string& parameter) const; -}; - diff --git a/src/Log.cpp b/src/Log.cpp deleted file mode 100644 index 6b78fe0..0000000 --- a/src/Log.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* -   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 -   Her Majesty the Queen in Right of Canada (Communications Research -   Center Canada) - -   Copyright (C) 2018 -   Matthias P. Braendli, matthias.braendli@mpb.li - -    http://www.opendigitalradio.org - */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. - */ - -#include <list> -#include <cstdarg> -#include <chrono> - -#include "Log.h" - -using namespace std; - -/* etiLog is a singleton used in all parts of ODR-DabMod to output log messages. - */ -Logger etiLog; - -void Logger::register_backend(std::shared_ptr<LogBackend> backend) -{ -    backends.push_back(backend); -} - - -void Logger::log(log_level_t level, const char* fmt, ...) -{ -    if (level == discard) { -        return; -    } - -    int size = 100; -    std::string str; -    va_list ap; -    while (1) { -        str.resize(size); -        va_start(ap, fmt); -        int n = vsnprintf((char *)str.c_str(), size, fmt, ap); -        va_end(ap); -        if (n > -1 && n < size) { -            str.resize(n); -            break; -        } -        if (n > -1) -            size = n + 1; -        else -            size *= 2; -    } - -    logstr(level, move(str)); -} - -void Logger::logstr(log_level_t level, std::string&& message) -{ -    if (level == discard) { -        return; -    } - -    /* Remove a potential trailing newline. -     * It doesn't look good in syslog -     */ -    if (message[message.length()-1] == '\n') { -        message.resize(message.length()-1); -    } - -    for (auto &backend : backends) { -        backend->log(level, message); -    } - -    { -        std::lock_guard<std::mutex> guard(m_cerr_mutex); -        std::cerr << levels_as_str[level] << " " << message << std::endl; -    } -} - - -LogLine Logger::level(log_level_t level) -{ -    return LogLine(this, level); -} - -LogToFile::LogToFile(const std::string& filename) : name("FILE") -{ -    FILE* fd = fopen(filename.c_str(), "a"); -    if (fd == nullptr) { -        fprintf(stderr, "Cannot open log file !"); -        throw std::runtime_error("Cannot open log file !"); -    } - -    log_file.reset(fd); -} - -void LogToFile::log(log_level_t level, const std::string& message) -{ -    if (level != log_level_t::discard) { -        const char* log_level_text[] = { -            "DEBUG", "INFO", "WARN", "ERROR", "ALERT", "EMERG"}; - -        // fprintf is thread-safe -        fprintf(log_file.get(), SYSLOG_IDENT ": %s: %s\n", -                log_level_text[(size_t)level], message.c_str()); -        fflush(log_file.get()); -    } -} - -void LogToSyslog::log(log_level_t level, const std::string& message) -{ -    if (level != log_level_t::discard) { -        int syslog_level = LOG_EMERG; -        switch (level) { -            case debug: syslog_level = LOG_DEBUG; break; -            case info:  syslog_level = LOG_INFO; break; -                        /* we don't have the notice level */ -            case warn:  syslog_level = LOG_WARNING; break; -            case error: syslog_level = LOG_ERR; break; -            default:    syslog_level = LOG_CRIT; break; -            case alert: syslog_level = LOG_ALERT; break; -            case emerg: syslog_level = LOG_EMERG; break; -        } - -        syslog(syslog_level, SYSLOG_IDENT " %s", message.c_str()); -    } -} diff --git a/src/Log.h b/src/Log.h deleted file mode 100644 index 18f8c99..0000000 --- a/src/Log.h +++ /dev/null @@ -1,157 +0,0 @@ -/* -   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 -   Her Majesty the Queen in Right of Canada (Communications Research -   Center Canada) - -   Copyright (C) 2018 -   Matthias P. Braendli, matthias.braendli@mpb.li - -    http://www.opendigitalradio.org - */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#ifdef HAVE_CONFIG_H -#   include "config.h" -#endif - -#include <syslog.h> -#include <cstdarg> -#include <cstdio> -#include <fstream> -#include <sstream> -#include <iostream> -#include <list> -#include <stdexcept> -#include <string> -#include <mutex> -#include <memory> - -#define SYSLOG_IDENT "ODR-DabMux" -#define SYSLOG_FACILITY LOG_LOCAL0 - -enum log_level_t {debug = 0, info, warn, error, alert, emerg, discard}; - -static const std::string levels_as_str[] = -    { "     ", "     ", "WARN ", "ERROR", "ALERT", "EMERG", "-----"} ; - -/** Abstract class all backends must inherit from */ -class LogBackend { -    public: -        virtual ~LogBackend() {}; -        virtual void log(log_level_t level, const std::string& message) = 0; -        virtual std::string get_name() const = 0; -}; - -/** A Logging backend for Syslog */ -class LogToSyslog : public LogBackend { -    public: -        LogToSyslog() : name("SYSLOG") { -            openlog(SYSLOG_IDENT, LOG_PID, SYSLOG_FACILITY); -        } - -        virtual ~LogToSyslog() { -            closelog(); -        } - -        void log(log_level_t level, const std::string& message); - -        std::string get_name() const { return name; } - -    private: -        const std::string name; - -        LogToSyslog(const LogToSyslog& other) = delete; -        const LogToSyslog& operator=(const LogToSyslog& other) = delete; -}; - -class LogToFile : public LogBackend { -    public: -        LogToFile(const std::string& filename); -        void log(log_level_t level, const std::string& message); -        std::string get_name() const { return name; } - -    private: -        const std::string name; - -        struct FILEDeleter{ void operator()(FILE* fd){ if(fd) fclose(fd);}}; -        std::unique_ptr<FILE, FILEDeleter> log_file; - -        LogToFile(const LogToFile& other) = delete; -        const LogToFile& operator=(const LogToFile& other) = delete; -}; - -class LogLine; - -class Logger { -    public: -        void register_backend(std::shared_ptr<LogBackend> backend); - -        /* Log the message to all backends */ -        void log(log_level_t level, const char* fmt, ...); - -        void logstr(log_level_t level, std::string&& message); - -        /* Return a LogLine for the given level -         * so that you can write etiLog.level(info) << "stuff = " << 21 */ -        LogLine level(log_level_t level); - -    private: -        std::list<std::shared_ptr<LogBackend> > backends; - -        std::mutex m_cerr_mutex; -}; - -extern Logger etiLog; - -// Accumulate a line of logs, using same syntax as stringstream -// The line is logged when the LogLine gets destroyed -class LogLine { -    public: -        LogLine(const LogLine& logline); -        const LogLine& operator=(const LogLine& other) = delete; -        LogLine(Logger* logger, log_level_t level) : -            logger_(logger) -        { -            level_ = level; -        } - -        // Push the new element into the stringstream -        template <typename T> -        LogLine& operator<<(T s) { -            if (level_ != discard) { -                os << s; -            } -            return *this; -        } - -        ~LogLine() -        { -            if (level_ != discard) { -                logger_->logstr(level_, os.str()); -            } -        } - -    private: -        std::ostringstream os; -        log_level_t level_; -        Logger* logger_; -}; - - diff --git a/src/RemoteControl.cpp b/src/RemoteControl.cpp deleted file mode 100644 index b32c21a..0000000 --- a/src/RemoteControl.cpp +++ /dev/null @@ -1,595 +0,0 @@ -/* -   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 -   Her Majesty the Queen in Right of Canada (Communications Research -   Center Canada) - -   Copyright (C) 2019 -   Matthias P. Braendli, matthias.braendli@mpb.li - -    http://www.opendigitalradio.org - */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. - */ -#include <list> -#include <string> -#include <iostream> -#include <string> -#include <boost/asio.hpp> -#include <boost/thread.hpp> - -#include "RemoteControl.h" - -using boost::asio::ip::tcp; -using namespace std; - -RemoteControllers rcs; - -RemoteControllerTelnet::~RemoteControllerTelnet() -{ -    m_active = false; -    m_io_service.stop(); - -    if (m_restarter_thread.joinable()) { -        m_restarter_thread.join(); -    } - -    if (m_child_thread.joinable()) { -        m_child_thread.join(); -    } -} - -void RemoteControllerTelnet::restart() -{ -    if (m_restarter_thread.joinable()) { -        m_restarter_thread.join(); -    } - -    m_restarter_thread = std::thread( -            &RemoteControllerTelnet::restart_thread, -            this, 0); -} - -RemoteControllable::~RemoteControllable() { -    rcs.remove_controllable(this); -} - -std::list<std::string> RemoteControllable::get_supported_parameters() const { -    std::list<std::string> parameterlist; -    for (const auto& param : m_parameters) { -        parameterlist.push_back(param[0]); -    } -    return parameterlist; -} - -void RemoteControllers::add_controller(std::shared_ptr<BaseRemoteController> rc) { -    m_controllers.push_back(rc); -} - -void RemoteControllers::enrol(RemoteControllable *rc) { -    controllables.push_back(rc); -} - -void RemoteControllers::remove_controllable(RemoteControllable *rc) { -    controllables.remove(rc); -} - -std::list< std::vector<std::string> > RemoteControllers::get_param_list_values(const std::string& name) { -    RemoteControllable* controllable = get_controllable_(name); - -    std::list< std::vector<std::string> > allparams; -    for (auto ¶m : controllable->get_supported_parameters()) { -        std::vector<std::string> item; -        item.push_back(param); -        try { -            item.push_back(controllable->get_parameter(param)); -        } -        catch (const ParameterError &e) { -            item.push_back(std::string("error: ") + e.what()); -        } - -        allparams.push_back(item); -    } -    return allparams; -} - -std::string RemoteControllers::get_param(const std::string& name, const std::string& param) { -    RemoteControllable* controllable = get_controllable_(name); -    return controllable->get_parameter(param); -} - -void RemoteControllers::check_faults() { -    for (auto &controller : m_controllers) { -        if (controller->fault_detected()) { -            etiLog.level(warn) << -                "Detected Remote Control fault, restarting it"; -            controller->restart(); -        } -    } -} - -RemoteControllable* RemoteControllers::get_controllable_(const std::string& name) -{ -    auto rc = std::find_if(controllables.begin(), controllables.end(), -            [&](RemoteControllable* r) { return r->get_rc_name() == name; }); - -    if (rc == controllables.end()) { -        throw ParameterError("Module name unknown"); -    } -    else { -        return *rc; -    } -} - -void RemoteControllers::set_param( -        const std::string& name, -        const std::string& param, -        const std::string& value) -{ -    etiLog.level(info) << "RC: Setting " << name << " " << param -        << " to " << value; -    RemoteControllable* controllable = get_controllable_(name); -    try { -        return controllable->set_parameter(param, value); -    } -    catch (const ios_base::failure& e) { -        etiLog.level(info) << "RC: Failed to set " << name << " " << param -        << " to " << value << ": " << e.what(); -        throw ParameterError("Cannot understand value"); -    } -} - -// This runs in a separate thread, because -// it would take too long to be done in the main loop -// thread. -void RemoteControllerTelnet::restart_thread(long) -{ -    m_active = false; -    m_io_service.stop(); - -    if (m_child_thread.joinable()) { -        m_child_thread.join(); -    } - -    m_child_thread = std::thread(&RemoteControllerTelnet::process, this, 0); -} - -void RemoteControllerTelnet::handle_accept( -        const boost::system::error_code& boost_error, -        boost::shared_ptr< boost::asio::ip::tcp::socket > socket, -        boost::asio::ip::tcp::acceptor& acceptor) -{ - -    const std::string welcome = "ODR-DabMux Remote Control CLI\n" -                                "Write 'help' for help.\n" -                                "**********\n"; -    const std::string prompt = "> "; - -    std::string in_message; -    size_t length; - -    if (boost_error) { -        etiLog.level(error) << "RC: Error accepting connection"; -        return; -    } - -    try { -        etiLog.level(info) << "RC: Accepted"; - -        boost::system::error_code ignored_error; - -        boost::asio::write(*socket, boost::asio::buffer(welcome), -                boost::asio::transfer_all(), -                ignored_error); - -        while (m_active && in_message != "quit") { -            boost::asio::write(*socket, boost::asio::buffer(prompt), -                    boost::asio::transfer_all(), -                    ignored_error); - -            in_message = ""; - -            boost::asio::streambuf buffer; -            length = boost::asio::read_until(*socket, buffer, "\n", ignored_error); - -            std::istream str(&buffer); -            std::getline(str, in_message); - -            if (length == 0) { -                etiLog.level(info) << "RC: Connection terminated"; -                break; -            } - -            while (in_message.length() > 0 && -                    (in_message[in_message.length()-1] == '\r' || -                     in_message[in_message.length()-1] == '\n')) { -                in_message.erase(in_message.length()-1, 1); -            } - -            if (in_message.length() == 0) { -                continue; -            } - -            etiLog.level(info) << "RC: Got message '" << in_message << "'"; - -            dispatch_command(*socket, in_message); -        } -        etiLog.level(info) << "RC: Closing socket"; -        socket->close(); -    } -    catch (const std::exception& e) -    { -        etiLog.level(error) << "Remote control caught exception: " << e.what(); -    } -} - -void RemoteControllerTelnet::process(long) -{ -    m_active = true; - -    while (m_active) { -        m_io_service.reset(); - -        tcp::acceptor acceptor(m_io_service, tcp::endpoint( -                    boost::asio::ip::address::from_string("127.0.0.1"), m_port) ); - - -        // Add a job to start accepting connections. -        boost::shared_ptr<tcp::socket> socket( -                new tcp::socket(acceptor.get_io_service())); - -        // Add an accept call to the service.  This will prevent io_service::run() -        // from returning. -        etiLog.level(info) << "RC: Waiting for connection on port " << m_port; -        acceptor.async_accept(*socket, -                boost::bind(&RemoteControllerTelnet::handle_accept, -                    this, -                    boost::asio::placeholders::error, -                    socket, -                    boost::ref(acceptor))); - -        // Process event loop. -        m_io_service.run(); -    } - -    etiLog.level(info) << "RC: Leaving"; -    m_fault = true; -} - -static std::vector<std::string> tokenise(const std::string& message) { -    stringstream ss(message); -    std::vector<std::string> all_tokens; -    std::string item; - -    while (std::getline(ss, item, ' ')) { -        all_tokens.push_back(move(item)); -    } -    return all_tokens; -} - - -void RemoteControllerTelnet::dispatch_command(tcp::socket& socket, string command) -{ -    vector<string> cmd = tokenise(command); - -    if (cmd[0] == "help") { -        reply(socket, -                "The following commands are supported:\n" -                "  list\n" -                "    * Lists the modules that are loaded and their parameters\n" -                "  show MODULE\n" -                "    * Lists all parameters and their values from module MODULE\n" -                "  get MODULE PARAMETER\n" -                "    * Gets the value for the specified PARAMETER from module MODULE\n" -                "  set MODULE PARAMETER VALUE\n" -                "    * Sets the value for the PARAMETER ofr module MODULE\n" -                "  quit\n" -                "    * Terminate this session\n" -                "\n"); -    } -    else if (cmd[0] == "list") { -        stringstream ss; - -        if (cmd.size() == 1) { -            for (auto &controllable : rcs.controllables) { -                ss << controllable->get_rc_name() << endl; - -                list< vector<string> > params = controllable->get_parameter_descriptions(); -                for (auto ¶m : params) { -                    ss << "\t" << param[0] << " : " << param[1] << endl; -                } -            } -        } -        else { -            reply(socket, "Too many arguments for command 'list'"); -        } - -        reply(socket, ss.str()); -    } -    else if (cmd[0] == "show") { -        if (cmd.size() == 2) { -            try { -                stringstream ss; -                list< vector<string> > r = rcs.get_param_list_values(cmd[1]); -                for (auto ¶m_val : r) { -                    ss << param_val[0] << ": " << param_val[1] << endl; -                } -                reply(socket, ss.str()); - -            } -            catch (const ParameterError &e) { -                reply(socket, e.what()); -            } -        } -        else { -            reply(socket, "Incorrect parameters for command 'show'"); -        } -    } -    else if (cmd[0] == "get") { -        if (cmd.size() == 3) { -            try { -                string r = rcs.get_param(cmd[1], cmd[2]); -                reply(socket, r); -            } -            catch (const ParameterError &e) { -                reply(socket, e.what()); -            } -        } -        else { -            reply(socket, "Incorrect parameters for command 'get'"); -        } -    } -    else if (cmd[0] == "set") { -        if (cmd.size() >= 4) { -            try { -                stringstream new_param_value; -                for (size_t i = 3; i < cmd.size(); i++) { -                    new_param_value << cmd[i]; - -                    if (i+1 < cmd.size()) { -                        new_param_value << " "; -                    } -                } - -                rcs.set_param(cmd[1], cmd[2], new_param_value.str()); -                reply(socket, "ok"); -            } -            catch (const ParameterError &e) { -                reply(socket, e.what()); -            } -            catch (const exception &e) { -                reply(socket, "Error: Invalid parameter value. "); -            } -        } -        else { -            reply(socket, "Incorrect parameters for command 'set'"); -        } -    } -    else if (cmd[0] == "quit") { -        reply(socket, "Goodbye"); -    } -    else { -        reply(socket, "Message not understood"); -    } -} - -void RemoteControllerTelnet::reply(tcp::socket& socket, string message) -{ -    boost::system::error_code ignored_error; -    stringstream ss; -    ss << message << "\r\n"; -    boost::asio::write(socket, boost::asio::buffer(ss.str()), -            boost::asio::transfer_all(), -            ignored_error); -} - - -#if defined(HAVE_RC_ZEROMQ) - -RemoteControllerZmq::~RemoteControllerZmq() { -    m_active = false; -    m_fault = false; - -    if (m_restarter_thread.joinable()) { -        m_restarter_thread.join(); -    } - -    if (m_child_thread.joinable()) { -        m_child_thread.join(); -    } -} - -void RemoteControllerZmq::restart() -{ -    if (m_restarter_thread.joinable()) { -        m_restarter_thread.join(); -    } - -    m_restarter_thread = std::thread(&RemoteControllerZmq::restart_thread, this); -} - -// This runs in a separate thread, because -// it would take too long to be done in the main loop -// thread. -void RemoteControllerZmq::restart_thread() -{ -    m_active = false; - -    if (m_child_thread.joinable()) { -        m_child_thread.join(); -    } - -    m_child_thread = std::thread(&RemoteControllerZmq::process, this); -} - -void RemoteControllerZmq::recv_all(zmq::socket_t& pSocket, std::vector<std::string> &message) -{ -    bool more = true; -    do { -        zmq::message_t msg; -        pSocket.recv(&msg); -        std::string incoming((char*)msg.data(), msg.size()); -        message.push_back(incoming); -        more = msg.more(); -    } while (more); -} - -void RemoteControllerZmq::send_ok_reply(zmq::socket_t &pSocket) -{ -    zmq::message_t msg(2); -    char repCode[2] = {'o', 'k'}; -    memcpy ((void*) msg.data(), repCode, 2); -    pSocket.send(msg, 0); -} - -void RemoteControllerZmq::send_fail_reply(zmq::socket_t &pSocket, const std::string &error) -{ -    zmq::message_t msg1(4); -    char repCode[4] = {'f', 'a', 'i', 'l'}; -    memcpy ((void*) msg1.data(), repCode, 4); -    pSocket.send(msg1, ZMQ_SNDMORE); - -    zmq::message_t msg2(error.length()); -    memcpy ((void*) msg2.data(), error.c_str(), error.length()); -    pSocket.send(msg2, 0); -} - -void RemoteControllerZmq::process() -{ -    m_fault = false; - -    // create zmq reply socket for receiving ctrl parameters -    try { -        zmq::socket_t repSocket(m_zmqContext, ZMQ_REP); - -        // connect the socket -        int hwm = 100; -        int linger = 0; -        repSocket.setsockopt(ZMQ_RCVHWM, &hwm, sizeof(hwm)); -        repSocket.setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); -        repSocket.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); -        repSocket.bind(m_endpoint.c_str()); - -        // create pollitem that polls the  ZMQ sockets -        zmq::pollitem_t pollItems[] = { {repSocket, 0, ZMQ_POLLIN, 0} }; -        while (m_active) { -            zmq::poll(pollItems, 1, 100); -            std::vector<std::string> msg; - -            if (pollItems[0].revents & ZMQ_POLLIN) { -                recv_all(repSocket, msg); - -                std::string command((char*)msg[0].data(), msg[0].size()); - -                if (msg.size() == 1 && command == "ping") { -                    send_ok_reply(repSocket); -                } -                else if (msg.size() == 1 && command == "list") { -                    size_t cohort_size = rcs.controllables.size(); -                    for (auto &controllable : rcs.controllables) { -                        std::stringstream ss; -                        ss << "{ \"name\": \"" << controllable->get_rc_name() << "\"," << -                            " \"params\": { "; - -                        list< vector<string> > params = controllable->get_parameter_descriptions(); -                        size_t i = 0; -                        for (auto ¶m : params) { -                            if (i > 0) { -                                ss << ", "; -                            } - -                            ss << "\"" << param[0] << "\": " << -                                "\"" << param[1] << "\""; - -                            i++; -                        } - -                        ss << " } }"; - -                        std::string msg_s = ss.str(); - -                        zmq::message_t zmsg(ss.str().size()); -                        memcpy ((void*) zmsg.data(), msg_s.data(), msg_s.size()); - -                        int flag = (--cohort_size > 0) ? ZMQ_SNDMORE : 0; -                        repSocket.send(zmsg, flag); -                    } -                } -                else if (msg.size() == 2 && command == "show") { -                    std::string module((char*) msg[1].data(), msg[1].size()); -                    try { -                        list< vector<string> > r = rcs.get_param_list_values(module); -                        size_t r_size = r.size(); -                        for (auto ¶m_val : r) { -                            std::stringstream ss; -                            ss << param_val[0] << ": " << param_val[1] << endl; -                            zmq::message_t zmsg(ss.str().size()); -                            memcpy(zmsg.data(), ss.str().data(), ss.str().size()); - -                            int flag = (--r_size > 0) ? ZMQ_SNDMORE : 0; -                            repSocket.send(zmsg, flag); -                        } -                    } -                    catch (const ParameterError &err) { -                        send_fail_reply(repSocket, err.what()); -                    } -                } -                else if (msg.size() == 3 && command == "get") { -                    std::string module((char*) msg[1].data(), msg[1].size()); -                    std::string parameter((char*) msg[2].data(), msg[2].size()); - -                    try { -                        std::string value = rcs.get_param(module, parameter); -                        zmq::message_t zmsg(value.size()); -                        memcpy ((void*) zmsg.data(), value.data(), value.size()); -                        repSocket.send(zmsg, 0); -                    } -                    catch (const ParameterError &err) { -                        send_fail_reply(repSocket, err.what()); -                    } -                } -                else if (msg.size() == 4 && command == "set") { -                    std::string module((char*) msg[1].data(), msg[1].size()); -                    std::string parameter((char*) msg[2].data(), msg[2].size()); -                    std::string value((char*) msg[3].data(), msg[3].size()); - -                    try { -                        rcs.set_param(module, parameter, value); -                        send_ok_reply(repSocket); -                    } -                    catch (const ParameterError &err) { -                        send_fail_reply(repSocket, err.what()); -                    } -                } -                else { -                    send_fail_reply(repSocket, -                            "Unsupported command. commands: list, show, get, set"); -                } -            } -        } -        repSocket.close(); -    } -    catch (const zmq::error_t &e) { -        etiLog.level(error) << "ZMQ RC error: " << std::string(e.what()); -    } -    catch (const std::exception& e) { -        etiLog.level(error) << "ZMQ RC caught exception: " << e.what(); -        m_fault = true; -    } -} - -#endif - diff --git a/src/RemoteControl.h b/src/RemoteControl.h deleted file mode 100644 index 0726b28..0000000 --- a/src/RemoteControl.h +++ /dev/null @@ -1,263 +0,0 @@ -/* -   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 -   Her Majesty the Queen in Right of Canada (Communications Research -   Center Canada) - -   Copyright (C) 2019 -   Matthias P. Braendli, matthias.braendli@mpb.li - -    http://www.opendigitalradio.org - -   This module adds remote-control capability to some of the dabmux modules. - */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#ifdef HAVE_CONFIG_H -#  include "config.h" -#endif - -#if defined(HAVE_RC_ZEROMQ) -#  include "zmq.hpp" -#endif - -#include <list> -#include <map> -#include <memory> -#include <string> -#include <atomic> -#include <iostream> -#include <boost/bind.hpp> -#include <boost/asio.hpp> -#include <boost/foreach.hpp> -#include <boost/tokenizer.hpp> -#include <thread> -#include <stdexcept> - -#include "Log.h" - -#define RC_ADD_PARAMETER(p, desc) {   \ -  std::vector<std::string> p; \ -  p.push_back(#p); \ -  p.push_back(desc); \ -  m_parameters.push_back(p); \ -} - -class ParameterError : public std::exception -{ -    public: -        ParameterError(std::string message) : m_message(message) {} -        ~ParameterError() throw() {} -        const char* what() const throw() { return m_message.c_str(); } - -    private: -        std::string m_message; -}; - -class RemoteControllable; - -/* Remote controllers (that recieve orders from the user) - * must implement BaseRemoteController - */ -class BaseRemoteController { -    public: -        /* When this returns one, the remote controller cannot be -         * used anymore, and must be restarted by dabmux -         */ -        virtual bool fault_detected() = 0; - -        /* In case of a fault, the remote controller can be -         * restarted. -         */ -        virtual void restart() = 0; - -        virtual ~BaseRemoteController() {} -}; - -/* Objects that support remote control must implement the following class */ -class RemoteControllable { -    public: -        RemoteControllable(const std::string& name) : -            m_rc_name(name) {} - -        RemoteControllable(const RemoteControllable& other) = delete; -        RemoteControllable& operator=(const RemoteControllable& other) = delete; - -        virtual ~RemoteControllable(); - -        /* return a short name used to identify the controllable. -         * It might be used in the commands the user has to type, so keep -         * it short -         */ -        virtual std::string get_rc_name() const { return m_rc_name; } - -        /* Return a list of possible parameters that can be set */ -        virtual std::list<std::string> get_supported_parameters() const; - -        /* Return a mapping of the descriptions of all parameters */ -        virtual std::list< std::vector<std::string> > -            get_parameter_descriptions() const -            { -                return m_parameters; -            } - -        /* Base function to set parameters. */ -        virtual void set_parameter( -                const std::string& parameter, -                const std::string& value) = 0; - -        /* Getting a parameter always returns a string. */ -        virtual const std::string get_parameter(const std::string& parameter) const = 0; - -    protected: -        std::string m_rc_name; -        std::list< std::vector<std::string> > m_parameters; -}; - -/* Holds all our remote controllers and controlled object. - */ -class RemoteControllers { -    public: -        void add_controller(std::shared_ptr<BaseRemoteController> rc); -        void enrol(RemoteControllable *rc); -        void remove_controllable(RemoteControllable *rc); -        void check_faults(); -        std::list< std::vector<std::string> > get_param_list_values(const std::string& name); -        std::string get_param(const std::string& name, const std::string& param); - -        void set_param( -                const std::string& name, -                const std::string& param, -                const std::string& value); - -        std::list<RemoteControllable*> controllables; - -    private: -        RemoteControllable* get_controllable_(const std::string& name); - -        std::list<std::shared_ptr<BaseRemoteController> > m_controllers; -}; - -extern RemoteControllers rcs; - -/* Implements a Remote controller based on a simple telnet CLI - * that listens on localhost - */ -class RemoteControllerTelnet : public BaseRemoteController { -    public: -        RemoteControllerTelnet() -            : m_active(false), -            m_io_service(), -            m_fault(false), -            m_port(0) { } - -        RemoteControllerTelnet(int port) -            : m_active(port > 0), -            m_io_service(), -            m_fault(false), -            m_port(port) -        { -            restart(); -        } - - -        RemoteControllerTelnet& operator=(const RemoteControllerTelnet& other) = delete; -        RemoteControllerTelnet(const RemoteControllerTelnet& other) = delete; - -        ~RemoteControllerTelnet(); - -        virtual bool fault_detected() { return m_fault; } - -        virtual void restart(); - -    private: -        void restart_thread(long); - -        void process(long); - -        void dispatch_command(boost::asio::ip::tcp::socket& socket, -                std::string command); - -        void reply(boost::asio::ip::tcp::socket& socket, std::string message); - -        void handle_accept( -                const boost::system::error_code& boost_error, -                boost::shared_ptr< boost::asio::ip::tcp::socket > socket, -                boost::asio::ip::tcp::acceptor& acceptor); - -        std::atomic<bool> m_active; - -        boost::asio::io_service m_io_service; - -        /* This is set to true if a fault occurred */ -        std::atomic<bool> m_fault; -        std::thread m_restarter_thread; - -        std::thread m_child_thread; - -        int m_port; -}; - -#if defined(HAVE_RC_ZEROMQ) -/* Implements a Remote controller using zmq transportlayer - * that listens on localhost - */ -class RemoteControllerZmq : public BaseRemoteController { -    public: -        RemoteControllerZmq() -            : m_active(false), m_fault(false), -            m_zmqContext(1), -            m_endpoint("") { } - -        RemoteControllerZmq(const std::string& endpoint) -            : m_active(not endpoint.empty()), m_fault(false), -            m_zmqContext(1), -            m_endpoint(endpoint), -            m_child_thread(&RemoteControllerZmq::process, this) { } - -        RemoteControllerZmq& operator=(const RemoteControllerZmq& other) = delete; -        RemoteControllerZmq(const RemoteControllerZmq& other) = delete; - -        ~RemoteControllerZmq(); - -        virtual bool fault_detected() { return m_fault; } - -        virtual void restart(); - -    private: -        void restart_thread(); - -        void recv_all(zmq::socket_t &pSocket, std::vector<std::string> &message); -        void send_ok_reply(zmq::socket_t &pSocket); -        void send_fail_reply(zmq::socket_t &pSocket, const std::string &error); -        void process(); - -        std::atomic<bool> m_active; - -        /* This is set to true if a fault occurred */ -        std::atomic<bool> m_fault; -        std::thread m_restarter_thread; - -        zmq::context_t m_zmqContext; - -        std::string m_endpoint; -        std::thread m_child_thread; -}; -#endif - diff --git a/src/crc.c b/src/crc.c deleted file mode 100644 index cc02473..0000000 --- a/src/crc.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the -   Queen in Right of Canada (Communications Research Center Canada) -   */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. -   */ - -#include "crc.h" -#ifndef _WIN32 -#    include <unistd.h> -#    include <netinet/in.h> -#endif -#include <stdio.h> -#include <fcntl.h> - -//#define CCITT       0x1021 - -uint8_t crc8tab[256] = { -    0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, -    0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, -    0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, -    0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, -    0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, -    0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, -    0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, -    0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, -    0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, -    0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, -    0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, -    0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, -    0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, -    0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, -    0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, -    0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, -    0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, -    0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, -    0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, -    0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, -    0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, -    0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, -    0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, -    0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, -    0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, -    0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, -    0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, -    0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, -    0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, -    0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, -    0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, -    0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 -}; - - -uint16_t crc16tab[256] = { -    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, -    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, -    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, -    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, -    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, -    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, -    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, -    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, -    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, -    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, -    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, -    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, -    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, -    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, -    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, -    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, -    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, -    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, -    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, -    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, -    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, -    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, -    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, -    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, -    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, -    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, -    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, -    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, -    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, -    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, -    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, -    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; - - -uint32_t crc32tab[256] = { -    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, -    0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, -    0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, -    0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, -    0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, -    0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, -    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, -    0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, -    0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, -    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, -    0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, -    0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, -    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, -    0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, -    0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, -    0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, -    0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, -    0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, -    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, -    0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, -    0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, -    0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, -    0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, -    0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, -    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, -    0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, -    0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, -    0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, -    0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, -    0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, -    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, -    0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, -    0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, -    0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, -    0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, -    0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, -    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, -    0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, -    0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, -    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, -    0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, -    0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, -    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, -    0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, -    0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, -    0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, -    0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, -    0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, -    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, -    0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, -    0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, -    0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, -    0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, -    0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, -    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, -    0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, -    0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, -    0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, -    0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, -    0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, -    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, -    0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, -    0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, -    0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 -}; - -// This function can be used to create a new table with a different polynom -void init_crc8tab(uint8_t l_code, uint8_t l_init) -{ -    unsigned i, j, msb; -    uint8_t nb; -    uint8_t crc; - -    for (i = 0; i < 256; ++i) { -        crc = l_init; -        nb = i ^ 0xff; -        for (j = 0; j < 8; ++j) { -            msb = (nb & (0x80 >> j)) && 1; -            msb ^= (crc >> 7); -            crc <<= 1; -            if (msb) -                crc ^= l_code; -        } -        crc8tab[i] = crc; -    } -} - - -void init_crc16tab(uint16_t l_code, uint16_t l_init) -{ -    unsigned i, j, msb; -    uint8_t nb; -    uint16_t crc; - -    for (i = 0; i < 256; ++i) { -        crc = l_init; -        nb = i ^ 0xff; -        for (j = 0; j < 8; ++j) { -            msb = (nb & (0x80 >> j)) && 1; -            msb ^= (crc >> 15); -            crc <<= 1; -            if (msb) -                crc ^= l_code; -        } -        crc ^= 0xff00; -        crc16tab[i] = crc; -    } -} - - -void init_crc32tab(uint32_t l_code, uint32_t l_init) -{ -    unsigned i, j, msb; -    uint8_t nb; -    uint32_t crc; - -    for (i = 0; i < 256; ++i) { -        crc = l_init; -        nb = i ^ 0xff; -        for (j = 0; j < 8; ++j) { -            msb = (nb & (0x80 >> j)) && 1; -            msb ^= (crc >> 31); -            crc <<= 1; -            if (msb) -                crc ^= l_code; -        } -        crc ^= 0xffffff00; -        crc32tab[i] = crc; -    } -} - - -uint8_t crc8(uint8_t l_crc, const void *lp_data, unsigned l_nb) -{ -    const uint8_t* data = (const uint8_t*)lp_data; -    while (l_nb--) { -        l_crc = crc8tab[l_crc ^ *(data++)]; -    } -    return (l_crc); -} - - -uint16_t crc16(uint16_t l_crc, const void *lp_data, unsigned l_nb) -{ -    const uint8_t* data = (const uint8_t*)lp_data; -    while (l_nb--) { -        l_crc = -            (l_crc << 8) ^ crc16tab[(l_crc >> 8) ^ *(data++)]; -    } -    return (l_crc); -} - - -uint32_t crc32(uint32_t l_crc, const void *lp_data, unsigned l_nb) -{ -    const uint8_t* data = (const uint8_t*)lp_data; -    while (l_nb--) { -        l_crc = -            (l_crc << 8) ^ crc32tab[((l_crc >> 24) ^ *(data++)) & 0xff]; -    } -    return (l_crc); -} diff --git a/src/crc.h b/src/crc.h deleted file mode 100644 index b1785a1..0000000 --- a/src/crc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the -   Queen in Right of Canada (Communications Research Center Canada) -   */ -/* -   This file is part of ODR-DabMux. - -   ODR-DabMux is free software: you can redistribute it and/or modify -   it under the terms of the GNU General Public License as -   published by the Free Software Foundation, either version 3 of the -   License, or (at your option) any later version. - -   ODR-DabMux is distributed in the hope that it will be useful, -   but WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -   GNU General Public License for more details. - -   You should have received a copy of the GNU General Public License -   along with ODR-DabMux.  If not, see <http://www.gnu.org/licenses/>. -   */ - -#ifndef _CRC -#define _CRC - -#ifdef HAVE_CONFIG_H -#   include "config.h" -#endif - -#ifndef _WIN32 -  #include <stdint.h> -#else -  #include <winsock2.h>	// For types... -  typedef BYTE uint8_t; -  typedef WORD uint16_t; -  typedef DWORD32 uint32_t; -#endif - - -#ifdef __cplusplus -extern "C" { // } -#endif - -void init_crc8tab(uint8_t l_code, uint8_t l_init); -uint8_t crc8(uint8_t l_crc, const void *lp_data, unsigned l_nb); -extern uint8_t crc8tab[]; - -void init_crc16tab(uint16_t l_code, uint16_t l_init); -uint16_t crc16(uint16_t l_crc, const void *lp_data, unsigned l_nb); -extern uint16_t crc16tab[]; - -void init_crc32tab(uint32_t l_code, uint32_t l_init); -uint32_t crc32(uint32_t l_crc, const void *lp_data, unsigned l_nb); -extern uint32_t crc32tab[]; - -#ifdef __cplusplus -} -#endif - -#endif //_CRC | 
