How do I receive data from NTP server?
Asked Answered
S

2

-2

I have no idea why send data is 48 bytes 010,0,0..., someone can explain? the problem is buffer for data received, I don't know how big he should be, and even if I receive data, how to make normal time from it?

Here's the code:

#include <iostream>

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_MEAN_AND_LEAN

#include <winsock2.h>
#include <windows.h>

#include <time.h>



using namespace std;

class HRException
{
public:
    HRException() :
        m_pMessage("") {}
    virtual ~HRException() {}
    HRException(const char *pMessage) :
        m_pMessage(pMessage) {}
    const char * what() { return m_pMessage; }
private:
    const char *m_pMessage;
};

const int  REQ_WINSOCK_VER = 2; // Minimum winsock version required
const char DEF_SERVER_NAME[] = "0.pl.pool.ntp.org";
const int  SERVER_PORT = 123;
const int  TEMP_BUFFER_SIZE = 128;

const char msg[48] = { 010,0,0,0,0,0,0,0,0 };


// IP number typedef for IPv4
typedef unsigned long IPNumber;

IPNumber FindHostIP(const char *pServerName)
{
    HOSTENT *pHostent;

    // Get hostent structure for hostname:
    if (!(pHostent = gethostbyname(pServerName)))
        throw HRException("could not resolve hostname.");

    // Extract primary IP address from hostent structure:
    if (pHostent->h_addr_list && pHostent->h_addr_list[0])
        return *reinterpret_cast<IPNumber*>(pHostent->h_addr_list[0]);

    return 0;
}

void FillSockAddr(sockaddr_in *pSockAddr, const char *pServerName, int portNumber)
{
    // Set family, port and find IP
    pSockAddr->sin_family = AF_INET;
    pSockAddr->sin_port = htons(portNumber);
    pSockAddr->sin_addr.S_un.S_addr = FindHostIP(pServerName);
}

bool RequestHeaders(const char *pServername)
{
    SOCKET      hSocket = INVALID_SOCKET;
    char        tempBuffer[TEMP_BUFFER_SIZE];
    sockaddr_in sockAddr = { 0 };
    bool        bSuccess = true;

    try
    {
        // Lookup hostname and fill sockaddr_in structure:
        cout << "Looking up hostname " << pServername << "... ";
        FillSockAddr(&sockAddr, pServername, SERVER_PORT);
        cout << "found.\n";

        // Create socket
        cout << "Creating socket... ";
        if ((hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
            throw HRException("could not create socket.");
        cout << "created.\n";

        // Connect to server
        cout << "Attempting to connect to " << inet_ntoa(sockAddr.sin_addr)
            << ":" << SERVER_PORT << "... ";
        if (connect(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) != 0)
            throw HRException("could not connect.");
        cout << "connected.\n";

        cout << "Sending request... ";

        // send request part 1
        if (send(hSocket, msg, sizeof(msg) , 0) == SOCKET_ERROR)
            throw HRException("failed to send data.");



        cout << "request sent.\n";

        cout << "Dumping received data...\n\n";
        // Loop to print all data

        recv(hSocket, tempBuffer, sizeof(tempBuffer), 0);  // <-- the problem
    ///
       //part where we take time out of tempBuffer

    ///







    }
    catch (HRException e)
    {
        cerr << "\nError: " << e.what() << endl;
        bSuccess = false;
    }

    if (hSocket != INVALID_SOCKET)
    {
        closesocket(hSocket);
    }
    return bSuccess;
}

int main(int argc, char* argv[])
{

    int iRet = 1;
    WSADATA wsaData;

    cout << "Initializing winsock... ";

    if (WSAStartup(MAKEWORD(REQ_WINSOCK_VER, 0), &wsaData) == 0)
    {
        // Check if major version is at least REQ_WINSOCK_VER
        if (LOBYTE(wsaData.wVersion) >= REQ_WINSOCK_VER)
        {
            cout << "initialized.\n";

            // Set default hostname:
            const char *pHostname = DEF_SERVER_NAME;

            // Set custom hostname if given on the commandline:
            if (argc > 1)
                pHostname = argv[1];

            iRet = !RequestHeaders(pHostname);
        }
        else
        {
            cerr << "required version not supported!";
        }

        cout << "Cleaning up winsock... ";

        // Cleanup winsock
        if (WSACleanup() != 0)
        {
            cerr << "cleanup failed!\n";
            iRet = 1;
        }
        cout << "done.\n";
    }
    else
    {
        cerr << "startup failed!\n";
    }
    int x;
    cin >> x;

    return iRet;
}

Most part of code is from madwizard.org

Salpingectomy answered 29/5, 2016 at 18:29 Comment(3)
I don't understand your question. Are you asking generally how to deal with the winsocks library? Or is this about NTP? I went to madwizard.com and I couldn't find any code there. Are you sure that is the source of this source code?Sedation
Possible duplicate of Time from NTP server in c++.Subtype
Sorry, it is madwizard.org not madwizard.com, my question is more about NTP(but im total noob in winsock also), i want to know why request for time to NTP server is 48bytes char array, and when it comes to getting data from NTP server how big should be buffer?Salpingectomy
S
1

Ok it works, main part of code:

        const char msg[48] = { 010,0,0,0,0,0,0,0,0 };

        if (send(hSocket, msg, sizeof(msg) , 0) == SOCKET_ERROR)
            throw HRException("failed to send data.");



        cout << "request sent.\n";

        cout << "Dumping received data...\n\n";


        char   tempBuffer[1024];
        int bytes =  recv(hSocket, tempBuffer, sizeof(tempBuffer), 0);  
        cout << "bytes received: " << bytes << endl;

        time_t tmit;
        tmit = ntohl(((time_t*)tempBuffer)[4]);
        tmit -= 2208988800U;

        cout << ctime(&tmit);

No idea why data that we send is

msg[48] = { 010,0,0,0,0,0,0,0,0 };

and why received data contains many numbers? for example if change code to

tmit = ntohl(((time_t*)tempBuffer)[6]);

I will get date 2008y, why?

Guys why so many minuses?, still waiting for an explanation :D

Here's whole code http://pastebin.com/Sv3ERGfV , dont forget to link ws2_32.lib

Salpingectomy answered 29/5, 2016 at 19:54 Comment(0)
T
0

Similar to my issue when trying to query the time from a self-hostet Windows-NTP-Server with the C++ library NTPClient which uses boost for the network tasks, msg[48] = { 010,0,0,0,0,0,0,0,0 }; configures the ntp.flags.mode. After comparing the network traffic of w32tm /stripchart /computer:10.159.96.65 using Wireshark, flag 27 or 11 seem to be the choices for my usecase: Comparison of NTP network packages

tmit = ntohl(((time_t*)tempBuffer)[6]); extracts the data from the received package. It looks like

  • 4 yields the reference time (last sync with timeserver I assume),
  • 8 the time when server received request and
  • 10 the transmit time (which should be almost equal).
Tournai answered 6/6, 2018 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.