Modified NTP library

Dependents:   NTPTest

Committer:
loopsva
Date:
Fri Nov 11 18:11:34 2016 +0000
Revision:
0:2c0aaa9a3e87
My modifications to TFTP State codes upon exit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
loopsva 0:2c0aaa9a3e87 1 /* NTPClient.cpp */
loopsva 0:2c0aaa9a3e87 2 /* Copyright (C) 2012 mbed.org, MIT License
loopsva 0:2c0aaa9a3e87 3 *
loopsva 0:2c0aaa9a3e87 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
loopsva 0:2c0aaa9a3e87 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
loopsva 0:2c0aaa9a3e87 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
loopsva 0:2c0aaa9a3e87 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
loopsva 0:2c0aaa9a3e87 8 * furnished to do so, subject to the following conditions:
loopsva 0:2c0aaa9a3e87 9 *
loopsva 0:2c0aaa9a3e87 10 * The above copyright notice and this permission notice shall be included in all copies or
loopsva 0:2c0aaa9a3e87 11 * substantial portions of the Software.
loopsva 0:2c0aaa9a3e87 12 *
loopsva 0:2c0aaa9a3e87 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
loopsva 0:2c0aaa9a3e87 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
loopsva 0:2c0aaa9a3e87 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
loopsva 0:2c0aaa9a3e87 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
loopsva 0:2c0aaa9a3e87 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
loopsva 0:2c0aaa9a3e87 18 */
loopsva 0:2c0aaa9a3e87 19
loopsva 0:2c0aaa9a3e87 20 //Debug is disabled by default
loopsva 0:2c0aaa9a3e87 21 #if 0
loopsva 0:2c0aaa9a3e87 22 //Enable debug
loopsva 0:2c0aaa9a3e87 23 #define __DEBUG__
loopsva 0:2c0aaa9a3e87 24 #include <cstdio>
loopsva 0:2c0aaa9a3e87 25 #define DBG(x, ...) std::printf("[NTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
loopsva 0:2c0aaa9a3e87 26 #define WARN(x, ...) std::printf("[NTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
loopsva 0:2c0aaa9a3e87 27 #define ERR(x, ...) std::printf("[NTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
loopsva 0:2c0aaa9a3e87 28
loopsva 0:2c0aaa9a3e87 29 #else
loopsva 0:2c0aaa9a3e87 30 //Disable debug
loopsva 0:2c0aaa9a3e87 31 #define DBG(x, ...)
loopsva 0:2c0aaa9a3e87 32 #define WARN(x, ...)
loopsva 0:2c0aaa9a3e87 33 #define ERR(x, ...)
loopsva 0:2c0aaa9a3e87 34
loopsva 0:2c0aaa9a3e87 35 #endif
loopsva 0:2c0aaa9a3e87 36
loopsva 0:2c0aaa9a3e87 37 #include "NTPClient.h"
loopsva 0:2c0aaa9a3e87 38
loopsva 0:2c0aaa9a3e87 39 #include "UDPSocket.h"
loopsva 0:2c0aaa9a3e87 40
loopsva 0:2c0aaa9a3e87 41 #include "mbed.h" //time() and set_time()
loopsva 0:2c0aaa9a3e87 42
loopsva 0:2c0aaa9a3e87 43 #define NTP_PORT 123
loopsva 0:2c0aaa9a3e87 44 #define NTP_CLIENT_PORT 0 //Random port
loopsva 0:2c0aaa9a3e87 45 #define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900)
loopsva 0:2c0aaa9a3e87 46
loopsva 0:2c0aaa9a3e87 47 //uint32_t LastNtpResult = 0;
loopsva 0:2c0aaa9a3e87 48
loopsva 0:2c0aaa9a3e87 49 NTPClient::NTPClient() : m_sock()
loopsva 0:2c0aaa9a3e87 50 {
loopsva 0:2c0aaa9a3e87 51
loopsva 0:2c0aaa9a3e87 52 }
loopsva 0:2c0aaa9a3e87 53
loopsva 0:2c0aaa9a3e87 54
loopsva 0:2c0aaa9a3e87 55
loopsva 0:2c0aaa9a3e87 56 NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
loopsva 0:2c0aaa9a3e87 57 {
loopsva 0:2c0aaa9a3e87 58 #ifdef __DEBUG__
loopsva 0:2c0aaa9a3e87 59 time_t ctTime;
loopsva 0:2c0aaa9a3e87 60 ctTime = time(NULL);
loopsva 0:2c0aaa9a3e87 61 DBG("Time is set to (UTC): %s", ctime(&ctTime));
loopsva 0:2c0aaa9a3e87 62 #endif
loopsva 0:2c0aaa9a3e87 63
loopsva 0:2c0aaa9a3e87 64 //Create & bind socket
loopsva 0:2c0aaa9a3e87 65 DBG("Binding socket");
loopsva 0:2c0aaa9a3e87 66 m_sock.bind(NTP_PORT); //Bind to a random port
loopsva 0:2c0aaa9a3e87 67
loopsva 0:2c0aaa9a3e87 68 m_sock.set_blocking(false, timeout); //Set not blocking
loopsva 0:2c0aaa9a3e87 69
loopsva 0:2c0aaa9a3e87 70 struct NTPPacket pkt;
loopsva 0:2c0aaa9a3e87 71
loopsva 0:2c0aaa9a3e87 72 //Now ping the server and wait for response
loopsva 0:2c0aaa9a3e87 73 DBG("Ping");
loopsva 0:2c0aaa9a3e87 74 //Prepare NTP Packet:
loopsva 0:2c0aaa9a3e87 75 pkt.li = 0; //Leap Indicator : No warning
loopsva 0:2c0aaa9a3e87 76 pkt.vn = 4; //Version Number : 4
loopsva 0:2c0aaa9a3e87 77 pkt.mode = 3; //Client mode
loopsva 0:2c0aaa9a3e87 78 pkt.stratum = 0; //Not relevant here
loopsva 0:2c0aaa9a3e87 79 pkt.poll = 0; //Not significant as well
loopsva 0:2c0aaa9a3e87 80 pkt.precision = 0; //Neither this one is
loopsva 0:2c0aaa9a3e87 81
loopsva 0:2c0aaa9a3e87 82 pkt.rootDelay = 0; //Or this one
loopsva 0:2c0aaa9a3e87 83 pkt.rootDispersion = 0; //Or that one
loopsva 0:2c0aaa9a3e87 84 pkt.refId = 0; //...
loopsva 0:2c0aaa9a3e87 85
loopsva 0:2c0aaa9a3e87 86 pkt.refTm_s = 0;
loopsva 0:2c0aaa9a3e87 87 pkt.origTm_s = 0;
loopsva 0:2c0aaa9a3e87 88 pkt.rxTm_s = 0;
loopsva 0:2c0aaa9a3e87 89 pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE
loopsva 0:2c0aaa9a3e87 90
loopsva 0:2c0aaa9a3e87 91 pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;
loopsva 0:2c0aaa9a3e87 92
loopsva 0:2c0aaa9a3e87 93 Endpoint outEndpoint;
loopsva 0:2c0aaa9a3e87 94
loopsva 0:2c0aaa9a3e87 95 if( outEndpoint.set_address(host, port) < 0)
loopsva 0:2c0aaa9a3e87 96 {
loopsva 0:2c0aaa9a3e87 97 m_sock.close();
loopsva 0:2c0aaa9a3e87 98 return NTP_DNS;
loopsva 0:2c0aaa9a3e87 99 }
loopsva 0:2c0aaa9a3e87 100
loopsva 0:2c0aaa9a3e87 101 //Set timeout, non-blocking and wait using select
loopsva 0:2c0aaa9a3e87 102 int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) );
loopsva 0:2c0aaa9a3e87 103 if (ret < 0 )
loopsva 0:2c0aaa9a3e87 104 {
loopsva 0:2c0aaa9a3e87 105 ERR("Could not send packet");
loopsva 0:2c0aaa9a3e87 106 m_sock.close();
loopsva 0:2c0aaa9a3e87 107 return NTP_CONN;
loopsva 0:2c0aaa9a3e87 108 }
loopsva 0:2c0aaa9a3e87 109
loopsva 0:2c0aaa9a3e87 110 //Read response
loopsva 0:2c0aaa9a3e87 111 Endpoint inEndpoint;
loopsva 0:2c0aaa9a3e87 112
loopsva 0:2c0aaa9a3e87 113 DBG("Pong");
loopsva 0:2c0aaa9a3e87 114 do
loopsva 0:2c0aaa9a3e87 115 {
loopsva 0:2c0aaa9a3e87 116 ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name
loopsva 0:2c0aaa9a3e87 117 if(ret < 0)
loopsva 0:2c0aaa9a3e87 118 {
loopsva 0:2c0aaa9a3e87 119 ERR("Could not receive packet");
loopsva 0:2c0aaa9a3e87 120 m_sock.close();
loopsva 0:2c0aaa9a3e87 121 return NTP_CONN;
loopsva 0:2c0aaa9a3e87 122 }
loopsva 0:2c0aaa9a3e87 123 } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 );
loopsva 0:2c0aaa9a3e87 124
loopsva 0:2c0aaa9a3e87 125 if(ret < sizeof(NTPPacket)) //TODO: Accept chunks
loopsva 0:2c0aaa9a3e87 126 {
loopsva 0:2c0aaa9a3e87 127 ERR("Receive packet size does not match");
loopsva 0:2c0aaa9a3e87 128 m_sock.close();
loopsva 0:2c0aaa9a3e87 129 return NTP_PRTCL;
loopsva 0:2c0aaa9a3e87 130 }
loopsva 0:2c0aaa9a3e87 131
loopsva 0:2c0aaa9a3e87 132 if( pkt.stratum == 0) //Kiss of death message : Not good !
loopsva 0:2c0aaa9a3e87 133 {
loopsva 0:2c0aaa9a3e87 134 ERR("Kissed to death!");
loopsva 0:2c0aaa9a3e87 135 m_sock.close();
loopsva 0:2c0aaa9a3e87 136 return NTP_PRTCL;
loopsva 0:2c0aaa9a3e87 137 }
loopsva 0:2c0aaa9a3e87 138
loopsva 0:2c0aaa9a3e87 139 //Correct Endianness
loopsva 0:2c0aaa9a3e87 140 pkt.refTm_s = ntohl( pkt.refTm_s );
loopsva 0:2c0aaa9a3e87 141 pkt.refTm_f = ntohl( pkt.refTm_f );
loopsva 0:2c0aaa9a3e87 142 pkt.origTm_s = ntohl( pkt.origTm_s );
loopsva 0:2c0aaa9a3e87 143 pkt.origTm_f = ntohl( pkt.origTm_f );
loopsva 0:2c0aaa9a3e87 144 pkt.rxTm_s = ntohl( pkt.rxTm_s );
loopsva 0:2c0aaa9a3e87 145 pkt.rxTm_f = ntohl( pkt.rxTm_f );
loopsva 0:2c0aaa9a3e87 146 pkt.txTm_s = ntohl( pkt.txTm_s );
loopsva 0:2c0aaa9a3e87 147 pkt.txTm_f = ntohl( pkt.txTm_f );
loopsva 0:2c0aaa9a3e87 148
loopsva 0:2c0aaa9a3e87 149 //Compute offset, see RFC 4330 p.13
loopsva 0:2c0aaa9a3e87 150 uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
loopsva 0:2c0aaa9a3e87 151 int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
loopsva 0:2c0aaa9a3e87 152 NTPLastResult = offset;
loopsva 0:2c0aaa9a3e87 153 DBG("Sent @%ul", pkt.txTm_s);
loopsva 0:2c0aaa9a3e87 154 DBG("Offset: %lld", offset);
loopsva 0:2c0aaa9a3e87 155 //Set time accordingly
loopsva 0:2c0aaa9a3e87 156 set_time( time(NULL) + offset );
loopsva 0:2c0aaa9a3e87 157
loopsva 0:2c0aaa9a3e87 158 #ifdef __DEBUG__
loopsva 0:2c0aaa9a3e87 159 ctTime = time(NULL);
loopsva 0:2c0aaa9a3e87 160 DBG("Time is now (UTC): %s", ctime(&ctTime));
loopsva 0:2c0aaa9a3e87 161 #endif
loopsva 0:2c0aaa9a3e87 162
loopsva 0:2c0aaa9a3e87 163 m_sock.close();
loopsva 0:2c0aaa9a3e87 164
loopsva 0:2c0aaa9a3e87 165 return NTP_OK;
loopsva 0:2c0aaa9a3e87 166 }
loopsva 0:2c0aaa9a3e87 167