Zoltan Hudak / NTPClient

Dependents:   WebTimer DISCO-F746NG_light_control_system_tth

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NTPClient.cpp Source File

NTPClient.cpp

00001 /* NTPClient.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 //Debug is disabled by default
00020 #if 0
00021 //Enable debug
00022 
00023 #define __DEBUG__
00024 #include <cstdio>
00025 #define DBG(x, ...)     std::printf("[NTPClient : DBG]"x "\r\n", ##__VA_ARGS__);
00026 #define WARN(x, ...)    std::printf("[NTPClient : WARN]"x "\r\n", ##__VA_ARGS__);
00027 #define ERR(x, ...)     std::printf("[NTPClient : ERR]"x "\r\n", ##__VA_ARGS__);
00028 
00029 #else
00030 
00031 //Disable debug
00032 #define DBG(x, ...)
00033 #define WARN(x, ...)
00034 #define ERR(x, ...)
00035 #endif
00036 
00037 #include "NetworkInterface.h"
00038 #include "NTPClient.h"
00039 #include "UDPSocket.h"
00040 #include "mbed.h"                           //time() and set_time()
00041 
00042 #define NTP_PORT            123
00043 #define NTP_CLIENT_PORT     0               //Random port
00044 
00045 #define NTP_TIMESTAMP_DELTA 2208988800ull   //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900)
00046 
00047 NTPClient::NTPClient(NetworkInterface& _m_intf) :
00048     m_intf(_m_intf)
00049 { }
00050 
00051 #ifdef htons
00052 #undef htons
00053 #endif /* htons */
00054 
00055 #ifdef htonl
00056 #undef htonl
00057 #endif /* htonl */
00058 
00059 #ifdef ntohs
00060 #undef ntohs
00061 #endif /* ntohs */
00062 
00063 #ifdef ntohl
00064 #undef ntohl
00065 #endif /* ntohl */
00066 
00067 #if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__))
00068 #define htons(x)    ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
00069 #define ntohs(x)    htons(x)
00070 #define htonl(x)    ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000UL) >> 8) | (((x) & 0xff000000UL) >> 24))
00071 #define ntohl(x)    htonl(x)
00072 #else
00073 #define htons(x)    (x)
00074 #define htonl(x)    (x)
00075 #define ntohl(x)    (x)
00076 #define ntohs(x)    (x)
00077 #endif
00078 
00079 /**
00080  * @brief
00081  * @note
00082  * @param
00083  * @retval
00084  */
00085 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
00086 {
00087 #ifdef __DEBUG__
00088     time_t  ctTime;
00089     ctTime = time(NULL);
00090     set_time(ctTime);
00091     DBG("Time is set to (UTC): %s", ctime(&ctTime));
00092 #endif
00093 
00094     SocketAddress   address(0, port);
00095     int             r = m_intf.gethostbyname(host, &address);
00096     if (r) {
00097         printf("error: 'gethostbyname(\"%s\")' failed with code %d\r\n", host, r);
00098     }
00099     else
00100     if (!address) {
00101         printf("error: 'gethostbyname(\"%s\")' returned null IP address\r\n", host);
00102     }
00103 
00104     //printf ("address: %s\n\r",address.get_ip_address());
00105     //Create & bind socket
00106     if (m_sock.open(&m_intf) < 0)
00107         printf("ERROR sock open \n\r");
00108     m_sock.set_timeout(timeout);
00109 
00110     struct NTPPacket    pkt;
00111     memset(&pkt, 0, sizeof(NTPPacket));
00112 
00113     //Now ping the server and wait for response
00114     DBG("Ping");
00115 
00116     //Prepare NTP Packet:
00117     pkt.li = 0;         //Leap Indicator : No warning
00118     pkt.vn = 4;         //Version Number : 4
00119     pkt.mode = 3;       //Client mode
00120     pkt.stratum = 0;    //Not relevant here
00121     pkt.poll = 0;       //Not significant as well
00122     pkt.precision = 0;  //Neither this one is
00123     int ret = m_sock.sendto(address, (char*) &pkt, sizeof(NTPPacket));
00124     if (ret < 0) {
00125         ERR("Could not send packet %d", ret);
00126         m_sock.close();
00127         return NTP_CONN;
00128     }
00129 
00130     //Read response
00131     DBG("Pong");
00132 
00133     ret = m_sock.recvfrom(&address, (char*) &pkt, sizeof(NTPPacket));   // LICIO
00134     if (ret < 0) {
00135         ERR("Could not receive packet %d", ret);
00136         m_sock.close();
00137         return NTP_CONN;
00138     }
00139 
00140     if (ret < sizeof(NTPPacket)) {
00141 
00142         //TODO: Accept chunks
00143         ERR("Receive packet size does not match");
00144         m_sock.close();
00145         return NTP_PRTCL;
00146     }
00147 
00148     if (pkt.stratum == 0) {
00149 
00150         //Kiss of death message : Not good !
00151         ERR("Kissed to death!");
00152         m_sock.close();
00153         return NTP_PRTCL;
00154     }
00155 
00156     //Correct Endianness
00157     pkt.refTm_s = ntohl(pkt.refTm_s);
00158     pkt.refTm_f = ntohl(pkt.refTm_f);
00159     pkt.origTm_s = ntohl(pkt.origTm_s);
00160     pkt.origTm_f = ntohl(pkt.origTm_f);
00161     pkt.rxTm_s = ntohl(pkt.rxTm_s);
00162     pkt.rxTm_f = ntohl(pkt.rxTm_f);
00163     pkt.txTm_s = ntohl(pkt.txTm_s);
00164     pkt.txTm_f = ntohl(pkt.txTm_f);
00165 
00166     // see RFC 4330 p.13
00167     time_t  txTm = (time_t) (pkt.txTm_s - NTP_TIMESTAMP_DELTA);
00168     set_time(txTm);
00169 
00170 #ifdef __DEBUG__
00171     ctTime = time(NULL);
00172     DBG("Time is now (UTC): %s", ctime(&ctTime));
00173 #endif
00174     m_sock.close();
00175 
00176     return NTP_OK;
00177 }