Click here to Skip to main content
15,796,456 members
Articles / Desktop Programming / System

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (15 votes)
3 Dec 2023LGPL31 min read 20.6K   614   28   5
Efficient and standalone library for NTP server/client utilizing pure C++
This library exposes both NTP server & NTP client, packet with settings and features, such as the utilization of drift tables. This library was tested on Windows enviroment 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
  • 22th 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 fater evaluaiton.
    • Added protocol version controling using client settings.
    • Fixed server's root delay and root dispersion transmision bug.
    • Fixed client's refid parsing bug
  • 1th December, 2023: 
    • Message printing buffer overrflow bug fix.
    • Ping bug fix.
    • Improve DateTime structure.
    • Client: added primitive handling for NTP control messages(Kiss of death codes).
  • 2th December, 2023: 
    • Client: Synch procedure bug fix.
    • Client: Adding the option to smooth out the clock adjustments.
    • Clinet: Changing default settings.
    • ClientsManager: Exposing query results, through callback.
  • 3th December, 2023: 
    • Cliemt+Server: Root dispersion & Root delay wrong format bug fixed.

License

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


Written By
Team Leader
Israel Israel
Born and raised in Israel, caught the programming virus at the age of 15.
Since than I can't stop coding.

Comments and Discussions

 
Questionexcellent Pin
Southmountain17-Nov-23 18:26
Southmountain17-Nov-23 18:26 
PraiseThanks for sharing this article! Pin
Member 161362079-Nov-23 1:56
Member 161362079-Nov-23 1:56 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA14-Oct-23 21:23
professionalȘtefan-Mihai MOGA14-Oct-23 21:23 
QuestionDead link Pin
Gisle Vanem28-Aug-23 1:26
Gisle Vanem28-Aug-23 1:26 
AnswerRe: Dead link Pin
JadBenAutho8-Oct-23 4:38
JadBenAutho8-Oct-23 4:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.