Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wont work on windows/ Rewrite done for openFrameworks #2

Open
adminfriso opened this issue Jan 26, 2023 · 2 comments
Open

Wont work on windows/ Rewrite done for openFrameworks #2

adminfriso opened this issue Jan 26, 2023 · 2 comments

Comments

@adminfriso
Copy link

I have successfully implemented your NTP client in an openframeworks application and it works perfectly on mac.

However on windows it would not compile because it cannot find the libaries

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <netinet/in.h>

have you experienced this already and maybe an idea for a solution?

@adminfriso
Copy link
Author

So i have rewritten it to work with open frameworks on both mac and windows and i would like to share my code

the main thing i overhauled was changing the udp requests to an openframeworks specific connector

@adminfriso
Copy link
Author

NtpClient.cpp

#include "NtpClient.h"

NTPClient::NTPClient(string hostname, uint16_t port) : hostname_(hostname), port_(port)
{
}

void NTPClient::build_connection()
{
    cout << "Creating socket with: " << hostname_ << endl;

    ofxUDPSettings settings;
    settings.sendTo(hostname_,  port_);
    settings.blocking = true;
    udpConnection.Setup(settings);
    udpConnection.SetTimeoutReceive(1);

}

NTPClient::~NTPClient() { 
    udpConnection.Close();
    }

uint64_t NTPClient::request_time()
{
    int response; // return result from writing/reading from the socket

    build_connection();

    std::cout << "Connecting\n";
    udpConnection.Connect(hostname_.c_str(), port_);

    NTPPacket packet = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    packet.li_vn_mode = 0x1b;

    std::cout << "Sending request\n";
    response = udpConnection.Send((char *)&packet, sizeof(NTPPacket));

    if (response < 0)
    {
        std::cerr << "ERROR writing to socket\n";
        return 0;
    }

    std::cout << "Reading request\n";
    response = udpConnection.Receive((char *)&packet, sizeof(NTPPacket));

    if (response < 0)
    {
        std::cerr << "ERROR reading from socket\n";
        close_socket();
        return 0;
    }

    // These two fields contain the time-stamp seconds as the packet left the NTP
    // server. The number of seconds correspond to the seconds passed since 1900.
    // ntohl() converts the bit/byte order from the network's to host's
    // "endianness".

    packet.transmited_timestamp_sec = ntohl(packet.transmited_timestamp_sec);           // Time-stamp seconds.
    packet.transmited_timestamp_sec_frac = ntohl(packet.transmited_timestamp_sec_frac); // Time-stamp fraction of a second.

    // Extract the 32 bits that represent the time-stamp seconds (since NTP epoch)
    // from when the packet left the server. Subtract 70 years worth of seconds
    // from the seconds since 1900. This leaves the seconds since the UNIX epoch
    // of 1970.
    // (1900)---------(1970)**********(Time Packet Left the Server)

    // seconds since UNIX epoch
    uint32_t txTm = packet.transmited_timestamp_sec - NTP_TIMESTAMP_DELTA;
    // convert seconds to milliseconds
    double milliseconds = (double)txTm * 1000l;

    return milliseconds;
}

void NTPClient::close_socket()
{
    udpConnection.Close();
}

NtpClient.h

#pragma once

#include "ofMain.h"
#include "ofxNetwork.h"

struct NTPPacket
{
    uint8_t li_vn_mode; // Eight bits. li, vn, and mode.
                        // li.   Two bits.   Leap indicator.
                        // vn.   Three bits. Version number of the protocol.
                        // mode. Three bits. Client will pick mode 3 for client.

    // Eight bits. Stratum level of the local clock.
    uint8_t stratum;

    // Eight bits. Maximum interval between successive messages.
    uint8_t poll;

    // Eight bits. Precision of the local clock.
    uint8_t precision;

    // 32 bits. Total round trip delay time.
    uint32_t rootDelay;

    // 32 bits. Max error aloud from primary clock source.
    uint32_t root_dispersion;

    // 32 bits. Reference clock identifier.
    uint32_t ref_id;

    // 32 bits. Reference time-stamp seconds.
    uint32_t ref_timestamp_sec;

    // 32 bits. Reference time-stamp fraction of a second.
    uint32_t ref_timestamp_sec_frac;

    // 32 bits. Originate time-stamp seconds.
    uint32_t orig_timestamp_sec;

    // 32 bits. Originate time-stamp fraction of a second.
    uint32_t orig_timestamp_sec_frac;

    // 32 bits. Received time-stamp seconds.
    uint32_t received_timestamp_sec;

    // 32 bits. Received time-stamp fraction of a second.
    uint32_t received_timestamp_sec_frac;

    // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
    uint32_t transmited_timestamp_sec;

    // 32 bits. Transmit time-stamp fraction of a second.
    uint32_t transmited_timestamp_sec_frac;
};

struct NTPClient
{
    NTPClient(string host, uint16_t port);
    ~NTPClient();

    /**
     * @brief Transmits an NTP request to the defined server and returns the
     * timestamp
     *
     * @return (uint64_t) the number of milliseconds since 1970. Return 0 if fail.
     */
    uint64_t request_time();

private:

    ofxUDPManager udpConnection;
    /**
     * @brief Converts from hostname to ip address
     *
     * @param hostname name of the host.
     * @return ip address. Return empty string if coun't find the ip.
     */
    string hostname_to_ip(const std::string &hostname);

    /// @brief Build the connection. Set all the params for the socket_client.
    void build_connection();

    /// @brief Close the connection. Set -1 to socket_fd.
    void close_socket();

    /// @brief NTP server IP address
    string hostname_;

    /// @brief NTP server port
    size_t port_;

    /// @brief Socket file descriptor
    int socket_fd;

    /// @brief Server address data structure
    struct sockaddr_in socket_client;

    /// @brief Delta between epoch time and ntp time
    static constexpr unsigned long long NTP_TIMESTAMP_DELTA{2208988800ull};
};

caller method


time_t getNtpTime()
    {

        int port = 123;
        string host = "YourHost.com";
        cout << "--- Sync NTP ----" << endl;
        cout << host << endl;

        NTPClient client{host, static_cast<uint16_t>(port)};

        auto epoch_server_ms = client.request_time();

        if (0 == epoch_server_ms)
        {
            cout << "Error requesting server time" << endl;
        }

        // The function ctime receives the timestamps in seconds.
        time_t epoch_server = (uint32_t)(epoch_server_ms / 1000);
        

        cout << "Server time: " << ctime(&epoch_server);
        cout << "Timestamp server: " << (uint32_t)epoch_server << "\n\n";

        time_t local_time;
        local_time = time(0);

        cout << "System time is " << (epoch_server - local_time) << " seconds off\n";
        cout << "--- Sync NTP Done ----" << endl;
        return epoch_server_ms;
    }
    

@adminfriso adminfriso changed the title Wont work on windows Wont work on windows/ Rewrite done for openFrameworks Jan 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant