diff options
| -rw-r--r-- | doc/example.mux | 7 | ||||
| -rw-r--r-- | src/ClockTAI.cpp | 59 | ||||
| -rw-r--r-- | src/ClockTAI.h | 6 | ||||
| -rw-r--r-- | src/DabMultiplexer.cpp | 15 | 
4 files changed, 72 insertions, 15 deletions
diff --git a/doc/example.mux b/doc/example.mux index 1ecffaf..48a89dc 100644 --- a/doc/example.mux +++ b/doc/example.mux @@ -50,6 +50,13 @@ general {      ; your file is still valid.      tist false +    ; The URLs used to fetch the TAI bulletin can be overridden if needed. +    ; URLs are given as a pipe-separated list, and the default value is: +    ;tai_clock_bulletins "https://www.ietf.org/timezones/data/leap-seconds.list|https://raw.githubusercontent.com/eggert/tz/master/leap-seconds.list" +    ; +    ; You may also use a file:// URL if you take care of updating the file +    ; yourself and store it locally. +      ; The management server is a simple TCP server that can present      ; statistics data (buffers, overruns, underruns, etc)      ; which can then be graphed a tool like Munin diff --git a/src/ClockTAI.cpp b/src/ClockTAI.cpp index 875fce2..7fef72b 100644 --- a/src/ClockTAI.cpp +++ b/src/ClockTAI.cpp @@ -69,8 +69,8 @@ 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> tai_urls = { -    "http://www.ietf.org/timezones/data/leap-seconds.list", +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",  }; @@ -86,10 +86,25 @@ static array<const char*, 2> tai_cache_locations = {      "/tmp/odr-dabmux-leap-seconds.cache",  }; -ClockTAI::ClockTAI() : +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() @@ -97,6 +112,8 @@ int ClockTAI::get_valid_offset()      int offset = 0;      bool offset_valid = false; +    std::unique_lock<std::mutex> lock(m_data_mutex); +      if (bulletin_is_valid()) {  #if TEST          etiLog.level(info) << "Bulletin already valid"; @@ -120,19 +137,22 @@ int ClockTAI::get_valid_offset()              offset_valid = true;          }          else { -            for (const auto url : tai_urls) { +            for (const auto url : m_bulletin_urls) {                  try { -                    download_tai_utc_bulletin(url);  #if TEST                      etiLog.level(info) << "Load bulletin from " << url;  #endif +                    download_tai_utc_bulletin(url.c_str());                      if (bulletin_is_valid()) { -#if TEST -                        etiLog.level(info) << "Bulletin from " << url << " valid"; -#endif                          offset = parse_ietf_bulletin(); +                        etiLog.level(debug) << "Loaded valid TAI Bulletin from " << +                            url << " giving offset=" << offset;                          offset_valid = true;                      } +                    else { +                        etiLog.level(debug) << "Skipping invalid TAI bulletin from " +                            << url; +                    }                  }                  catch (const runtime_error& e) {                      etiLog.level(warn) << @@ -171,12 +191,14 @@ int ClockTAI::get_valid_offset()  int ClockTAI::get_offset()  {      using namespace std::chrono; -    auto time_now = system_clock::now(); +    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; @@ -185,7 +207,14 @@ int ClockTAI::get_offset()  #else          // First time we run we must block until we know          // the offset -        m_offset = get_valid_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 = system_clock::now();  #endif @@ -196,6 +225,7 @@ int ClockTAI::get_offset()      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)); @@ -211,8 +241,8 @@ int ClockTAI::get_offset()                      }                      catch (const download_failed&) {                          etiLog.level(warn) << -                            "TAI-UTC download failed, will retry in " + -                            to_string(download_retry_interval_hours) + " hour(s)"; +                            "TAI-UTC download failed, will retry in " << +                            download_retry_interval_hours << " hour(s)";                      }  #ifdef TEST                      wait_longer = false; @@ -409,6 +439,9 @@ int64_t ClockTAI::bulletin_expiry_delay() const                  std::atoll(expiry_data_str.c_str()) - ntp_unix_offset;              if (expiry_unix > now) { +#ifdef TEST +                etiLog.level(info) << "Bulletin expires in " << expiry_unix - now; +#endif                  return expiry_unix - now;              }          } @@ -516,7 +549,7 @@ int main(int argc, char **argv)  {      using namespace std; -    ClockTAI tai; +    ClockTAI tai({});      while (wait_longer) {          try { diff --git a/src/ClockTAI.h b/src/ClockTAI.h index e0dc439..4436ba9 100644 --- a/src/ClockTAI.h +++ b/src/ClockTAI.h @@ -40,6 +40,8 @@  #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. @@ -49,7 +51,7 @@  /* Loads, parses and represents TAI-UTC offset information from the IETF bulletin */  class ClockTAI : public RemoteControllable {      public: -        ClockTAI(); +        ClockTAI(const std::vector<std::string>& bulletin_urls);          // Fetch the bulletin from the IETF website and return the current          // TAI-UTC offset. @@ -81,6 +83,8 @@ class ClockTAI : public RemoteControllable {          int m_offset = 0;          int m_offset_valid = false; +        std::vector<std::string> m_bulletin_urls; +          mutable std::stringstream m_bulletin;          std::chrono::system_clock::time_point m_bulletin_download_time; diff --git a/src/DabMultiplexer.cpp b/src/DabMultiplexer.cpp index 84d9704..719e767 100644 --- a/src/DabMultiplexer.cpp +++ b/src/DabMultiplexer.cpp @@ -66,6 +66,19 @@ const unsigned short BitRateTable[64] = {      384, 384, 384  }; +static vector<string> split_pipe_separated_string(const std::string& s) +{ +    stringstream ss; +    ss << s; + +    string elem; +    vector<string> components; +    while (getline(ss, elem, '|')) { +        components.push_back(elem); +    } +    return components; +} +  DabMultiplexer::DabMultiplexer(          boost::property_tree::ptree pt) :      RemoteControllable("mux"), @@ -76,7 +89,7 @@ DabMultiplexer::DabMultiplexer(      currentFrame(0),      ensemble(std::make_shared<dabEnsemble>()),      m_tai_clock_required(false), -    m_clock_tai(), +    m_clock_tai(split_pipe_separated_string(pt.get("general.tai_clock_bulletins", ""))),      fig_carousel(ensemble)  {      RC_ADD_PARAMETER(frames,  | 
