NTPResult NTPClient::setTime()

in AZ3166/src/cores/arduino/NTPClient/NTPClient.cpp [36:134]


NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
{
    if (host == NULL || host[0] == 0)
    {
        return NTP_DNS;
    }

    //Create & bind socket
    m_sock.set_blocking(false);
    m_sock.set_timeout(timeout);

    struct NTPPacket pkt;

    //Now ping the server and wait for response
    //Prepare NTP Packet:
    pkt.li = 0; //Leap Indicator : No warning
    pkt.vn = 4; //Version Number : 4
    pkt.mode = 3; //Client mode
    pkt.stratum = 0; //Not relevant here
    pkt.poll = 0; //Not significant as well
    pkt.precision = 0; //Neither this one is

    pkt.rootDelay = 0; //Or this one
    pkt.rootDispersion = 0; //Or that one
    pkt.refId = 0; //...

    pkt.refTm_s = 0;
    pkt.origTm_s = 0;
    pkt.rxTm_s = 0;
    pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE

    pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;

    SocketAddress outEndpoint(host, port);

    if(m_net->gethostbyname(host, &outEndpoint)!= 0)
    {
        m_sock.close();
        return NTP_DNS;
    }

    //Set timeout, non-blocking and wait using select
    int ret = m_sock.sendto(outEndpoint, (char*)&pkt, sizeof(NTPPacket) );
    if (ret < 0 )
    {
        m_sock.close();
        return NTP_CONN;
    }

    SocketAddress recvAddress;
    recvAddress.set_ip_address(outEndpoint.get_ip_address());
    recvAddress.set_port(port);
    ret = m_sock.recvfrom(&recvAddress, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name
    if (ret > 0)
    {
        if (strcmp(outEndpoint.get_ip_address(), recvAddress.get_ip_address()) != 0)
        {
          m_sock.close();
          return NTP_CONN;
        }
    }
    else
    {
        m_sock.close();
        return NTP_CONN;
    }

    if(ret < (int)sizeof(NTPPacket)) //TODO: Accept chunks
    {
        m_sock.close();
        return NTP_PRTCL;
    }

    if( pkt.stratum == 0)  //Kiss of death message : Not good !
    {
        m_sock.close();
        return NTP_PRTCL;
    }

    //Correct Endianness
    pkt.refTm_s = ntohl( pkt.refTm_s );
    pkt.refTm_f = ntohl( pkt.refTm_f );
    pkt.origTm_s = ntohl( pkt.origTm_s );
    pkt.origTm_f = ntohl( pkt.origTm_f );
    pkt.rxTm_s = ntohl( pkt.rxTm_s );
    pkt.rxTm_f = ntohl( pkt.rxTm_f );
    pkt.txTm_s = ntohl( pkt.txTm_s );
    pkt.txTm_f = ntohl( pkt.txTm_f );

    //Compute offset, see RFC 4330 p.13
    uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
    int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
    //Set time accordingly
    set_time( time(NULL) + offset );

    m_sock.close();

    return NTP_OK;
}