API Documentation
Loading...
Searching...
No Matches
NtpClient.h
Go to the documentation of this file.
1#pragma once
2#include <NDEVR/ItemDownloader.h>
3#include <NDEVR/String.h>
4#include <cassert>
5
6#include <memory>
7
8#include <QtCore/QObject>
9#include <QtNetwork/QHostAddress>
10#include <QtNetwork/QUdpSocket>
11#include <QHostInfo>
12#include <NDEVR/NtpPacketFlags.h>
13#include <NDEVR/NtpTimestamp.h>
14#include <NDEVR/NtpPacket.h>
15#include <NDEVR/NtpMode.h>
16#include <NDEVR/NtpReply.h>
17namespace NDEVR
18{
19 /**
20 * NTP client.
21 */
22 class NtpClient : public TimeRequest
23 {
24 Q_OBJECT;
25 public:
26 NtpClient(const String& host, uint02 bind_port, uint02 remote_port)
27 {
28 QHostInfo::lookupHost(host.getAs<QString>(), [this, bind_port, remote_port](const QHostInfo& host)
29 {
30 if (host.error() != QHostInfo::NoError)
31 {
32 emit errorOccurredSignal(0);
33 return;
34 }
35 QList<QHostAddress> addresses = host.addresses();
36 if(addresses.size() > 0)
37 {
38 if (bind(QHostAddress::Any, bind_port))
39 sendRequest(addresses[0], remote_port);
40 else if (bind(QHostAddress::Any, bind_port + 1))
41 sendRequest(addresses[0], remote_port);
42 else if (bind(QHostAddress::Any, bind_port + 2))
43 sendRequest(addresses[0], remote_port);
44 else
45 emit errorOccurredSignal(0);
46 }
47 else
48 {
49 emit errorOccurredSignal(0);
50 }
51 });
52 }
53 /**
54 * Virtual destructor.
55 */
56 virtual ~NtpClient() {}
57
58 /**
59 * @param bindAddress Network address to bind upd socket to. It's passed to `QUdpSocket::bind`.
60 * @param bindPort Network port to bind udp socket to.
61 * @return Whether the socket was successfully bound.
62 */
63 bool bind(const QHostAddress& bindAddress = QHostAddress::Any, quint16 bindPort = 0)
64 {
65 m_socket.reset(new QUdpSocket(this));
66 if (!m_socket->bind(bindAddress, bindPort))
67 return false;
68
69 connect(m_socket.get(), &QUdpSocket::readyRead, this, &NtpClient::readPendingDatagrams);
70 connect(m_socket.get(), &QUdpSocket::errorOccurred, this, [this]
71 {
72 emit errorOccurredSignal(0);
73 });
74 return true;
75 }
76
77 /**
78 * Sends NTP request.
79 *
80 * @param address NTP server address.
81 * @param port NTP server port.
82 * @returns Whether the NTP request was successfully sent.
83 */
84 bool sendRequest(const String& address, quint16 port)
85 {
86 return sendRequest(QHostAddress(address.getAs<QString>()), port);
87
88 }
89 bool sendRequest(const QHostAddress& address, quint16 port)
90 {
91 assert(m_socket->state() == QAbstractSocket::BoundState); // Call bind() first.
92 NtpPacket packet;
93 memset(&packet, 0, sizeof(packet));
95 packet.flags.versionNumber = 4;
97 if (m_socket->writeDatagram(reinterpret_cast<const char*>(&packet), sizeof(packet), address, port) < 0)
98 return false;
99
100 return true;
101 }
102 const QUdpSocket* socket() const {
103 return m_socket.get();
104 }
105
106 Q_SIGNALS:
107 /**
108 * This signal is emitted whenever NTP reply is received.
109 *
110 * @param address Address of the server that sent this reply.
111 * @param port Port of the server that sent this reply.
112 * @param reply NTP reply.
113 */
114 void replyReceived(const QHostAddress& address, quint16 port, const NtpReply& reply);
115
116 private Q_SLOTS:
117 void readPendingDatagrams()
118 {
119 while (m_socket->hasPendingDatagrams()) {
120 NtpFullPacket packet;
121 memset(&packet, 0, sizeof(packet));
122
123 QHostAddress address;
124 quint16 port;
125 if (m_socket->readDatagram(reinterpret_cast<char*>(&packet), sizeof(packet), &address, &port) < cast<qint64>(sizeof(NtpPacket)))
126 continue;
127
128 m_reply = NtpReply(packet, Time::SystemTime());
129 emit replyReceived(address, port, NtpReply(packet, Time::SystemTime()));
130 emit finishedSignal();
131 }
132 }
133 virtual Time serverTime() const override
134 {
135 return m_reply.originTime();
136 }
137 virtual Time rxTime() const override
138 {
139 return m_reply.destinationTime();
140 }
141 virtual Time txTime() const override
142 {
143 return m_reply.transmitTime();
144 }
145 private:
146 NtpReply m_reply;
147 std::unique_ptr<QUdpSocket> m_socket;
148 };
149}
Definition NtpClient.h:23
bool bind(const QHostAddress &bindAddress=QHostAddress::Any, quint16 bindPort=0)
Definition NtpClient.h:63
bool sendRequest(const QHostAddress &address, quint16 port)
Definition NtpClient.h:89
NtpClient(const String &host, uint02 bind_port, uint02 remote_port)
Definition NtpClient.h:26
const QUdpSocket * socket() const
Definition NtpClient.h:102
virtual ~NtpClient()
Definition NtpClient.h:56
bool sendRequest(const String &address, quint16 port)
Definition NtpClient.h:84
void replyReceived(const QHostAddress &address, quint16 port, const NtpReply &reply)
Definition NtpReply.h:14
The core String class for the software.
Definition String.h:47
t_type getAs() const
Definition String.h:341
static NDEVR_BASE_API Time SystemTime()
Retrieves the current system time.
Definition ItemDownloader.h:70
Definition ACIColor.h:37
@ ClientMode
Definition NtpEnums.h:21
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:379
uint16_t uint02
-Defines an alias representing a 2 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:86
Definition NtpPacket.h:79
unsigned char versionNumber
Definition NtpPacket.h:16
unsigned char mode
Definition NtpPacket.h:13
Definition NtpPacket.h:28
NtpTimestamp transmitTimestamp
Definition NtpPacket.h:60
NtpPacketFlags flags
Definition NtpPacket.h:30
Definition NtpTimestamp.h:13