Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / system

NTP/SNTP v4/v3 Server/Client C++

5.00/5 (20 votes)
8 Aug 2024LGPL32 min read 58.8K   1.7K  
Efficient and standalone library for NTP server/client utilizing pure C++
This library exposes both NTP server & NTP client, packed with settings and features, such as the utilization of drift tables. This library was tested both on windows (Visual Studio) and Ubuntu (Codeblocks) but is 99.9% compatible with other operating systems.

Introduction

After spending some time finding reliable native NTP server & client implementation, and falling short, I've decided on implementing one by myself, other servers/clients implementation had various issues and compatibility problems.

Both server and client do not modify by default the machine time (although it has the capability).

Background

The need came from the requirement to have full control over time synchronization mechanism on a system without reeling on/effecting the system clock, while moitoring NTP deviecs that queue for time.

Credit: A good starting point was the NTP-Client project by Jakub Parez at https://github.com/parezj/NTP-Client/tree/master.

Image 1

Using the Code

C#
//The included unit tests show examples for both server & client.

ntp::ClientSettings cs;

cs.lts = ntp::LocalTimeSource::InternalClock;
    cs.fta.delta_avg_min = std::chrono::microseconds::min();
    cs.fta.delta_stdev_min = std::chrono::microseconds(500);
    cs.fta.fine_adjustment_duration = std::chrono::seconds(60);

    cs.error_callback = [](const ntp::IClient& client, 
                        std::string error_string, void* userParam) {
        std::cout << "NTP client error: " << error_string << std::endl;
    };

    cs.warnning_callback = [](const ntp::IClient& client, 
                           std::string warn_string, void* userParam) {
        std::cout << "NTP client warning: " << warn_string << std::endl;
    };

    cs.clockset_callback = [](const ntp::IClient& client, 
                           ManagedClockPtr new_clock, void* userParam) {
        std::cout << "NTP client clockset: " << 
        new_clock->now().as_string() << std::endl;
    };

    auto ntp_client = ntp::IClient::create_instance();
    ntp_client->init(cs);
     auto res =  ntp_client->query(ep, false);//once created, 
                             //client can query a server given an endpoint.

//Server is actually a lot simpler once defining the sources of the clock:

auto ntp_server = ntp::IServer::create_instance();
    ntp::IServer::ServerSettings setup;

    if (use_external_time_source) {
        auto mng = StartInitClientsManager(false);
        mng->wait_initialzed(std::chrono::milliseconds(-1));
        setup.time_source = mng;
    }

    setup.error_callback = [](const ntp::IServer& server, 
                              std::string error_string, void* userParam) {
        std::cout << "NTP server error: " << error_string << std::endl;
    };

    setup.warnning_callback = [](const ntp::IServer& server, 
                                 std::string warn_string, void* userParam) {
        std::cout << "NTP server warning: " << warn_string << std::endl;
    };

    setup.client_serverd_callback = [](const ntp::IServer& server, 
                                       std::string client_addr, void* userParam) {
        std::cout << "NTP server serverd the client " << client_addr <<std::endl;
    };

    if(!ntp_server->init(setup))
        return false;

    std::this_thread::sleep_for(std::chrono::hours(10));

Points of Interest

One thing I've learned is the complexity of time "synchronization", and how sensitive it is to various factors.

History

  • 26th August, 2023
    • Initial version
  • 22nd November, 2023
    • Bug fixes, performance improvements
  • 29th November, 2023
    • Improved API
    • IP V6 support
    • Shorter server evaluation time
    • Adding servers evaluation method enum to choose accuracy over faster evaluation
    • Added protocol version controlling using client settings
    • Fixed server's root delay and root dispersion transmission bug
    • Fixed client's refid parsing bug
  • 1st December, 2023
    • Message printing buffer overflow bug fix
    • Ping bug fix
    • Improve DateTime structure
    • Client: Added primitive handling for NTP control messages (Kiss of death codes)
  • 2nd December, 2023
    • Client: Synch procedure bug fix
    • Client: Adding the option to smooth out the clock adjustments
    • Client: Changing default settings
    • ClientsManager: Exposing query results, through callback
  • 3rd December, 2023
    • Client+Server: Root dispersion & Root delay wrong format bug fixed.
  • 27th December, 2023
    • Added full Linux/Ubunto support.
    • Codeblocks IDE support.
    • Supporting NTP Eras.
    • Minor bug fix.
  • 3rd March, 2024
    • Improved leap indicator treatment.
  • 15th Jul, 2024
    • Adding to server code response mode for controlling the response to requests( ignore, flag as out of synch, flag as access denied)
  • 8th Aug, 2024
    • Bug fixed.
    • Adding optional dynamic clock update strategy interface plugin.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)