NTP Client for the mbed networking libraries

Dependents:   NTPClient_HelloWorld temp_FIAP NTPClient_Wifly_HelloWorld RTOSTest ... more

Fork of NTPClientLib by Donatien Garnier

Committer:
donatien
Date:
Fri Jul 27 08:49:34 2012 +0000
Revision:
1:b221a8765b3f
Parent:
0:04a82df0f587
Child:
2:9a64a50df235
Initial commit;

Who changed what in which revision?

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