Click here to Skip to main content
15,886,919 members
Articles / Desktop Programming / System
Article

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (19 votes)
2 Mar 2024LGPL31 min read 39.9K   1.1K   34   6
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.

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

 
GeneralMy vote of 5 Pin
ZeusT28-Dec-23 9:04
ZeusT28-Dec-23 9:04 
Questionexcellent Pin
Southmountain17-Nov-23 17:26
Southmountain17-Nov-23 17:26 
PraiseThanks for sharing this article! Pin
Member 161362079-Nov-23 0:56
Member 161362079-Nov-23 0:56 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA14-Oct-23 20:23
professionalȘtefan-Mihai MOGA14-Oct-23 20:23 
QuestionDead link Pin
Gisle Vanem28-Aug-23 0:26
Gisle Vanem28-Aug-23 0:26 
AnswerRe: Dead link Pin
JadBenAutho8-Oct-23 3:38
JadBenAutho8-Oct-23 3: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.