A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

udp/ntp/ntpclientquery.c

Committer:
andrewboyson
Date:
2019-01-22
Revision:
113:904b40231907
Child:
116:60521b29e4c9

File content as of revision 113:904b40231907:

#include <stdint.h>
#include <string.h>
#include <stdbool.h>

#include      "log.h"
#include      "clk.h"
#include  "mstimer.h"
#include  "clktime.h"
#include   "clkntp.h"
#include   "clkutc.h"
#include   "clkgov.h"
#include    "clktm.h"
#include      "net.h"
#include      "ntp.h"
#include "ntpclient.h"
#include      "dns.h"
#include      "ip4.h"
#include    "ar4.h"
#include    "ar6.h"
#include    "arp.h"
#include    "eth.h"
#include    "nr4.h"
#include    "nr6.h"
#include "ip6addr.h"
#include    "mac.h"
#include "action.h"

#define ONE_BILLION 1000000000ULL
#define ONE_MILLION     1000000LL

char    NtpClientQueryServerName[DNS_MAX_LABEL_LENGTH+1]; 
int32_t NtpClientQueryInitialInterval;                    
int32_t NtpClientQueryNormalInterval;                     
int32_t NtpClientQueryRetryInterval;                      

bool       NtpClientQuerySendRequestsViaIp4 = false;
uint32_t   NtpClientQueryServerIp4;
char       NtpClientQueryServerIp6[16];

static uint64_t startNtpMs = 0;
static int  intervalTypeNtp = NTP_QUERY_INTERVAL_INITIAL;
static bool intervalCompleteNtp()
{
    uint32_t interval;
    switch(intervalTypeNtp)
    {
        case NTP_QUERY_INTERVAL_INITIAL: interval = NtpClientQueryInitialInterval; break;
        case NTP_QUERY_INTERVAL_NORMAL:  interval = NtpClientQueryNormalInterval;  break;
        case NTP_QUERY_INTERVAL_RETRY:   interval = NtpClientQueryRetryInterval;   break;
    }
    return MsTimerHasElapsed(startNtpMs, interval * 1000);
}
void NtpClientQueryStartInterval(int type)
{
    startNtpMs = MsTimerCount;
    intervalTypeNtp = type;
}

static bool resolve4(char* server, uint32_t* pIp)
{
    //Check if have IP, if not, then request it and stop
    Nr4NameToIp(server, pIp);
    if (!*pIp)
    {
        Nr4MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
        return false;
    }

    //Check if have MAC and, if not, request it and stop
    char mac[6];
    Ar4IpToMac(*pIp, mac);
    if (MacIsEmpty(mac))
    {
        Ar4MakeRequestForMacFromIp(*pIp); //The request is only repeated if made after a freeze time - call as often as you want.
        return false;
    }
    
    return true;
}
static bool resolve6(char* server, char* ip)
{
    //Check if have IP, if not, then request it and stop
    Nr6NameToIp(server, ip);
    if (Ip6AddressIsEmpty(ip))
    {
        Nr6MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
        return false;
    }

    //Check if have MAC and, if not, request it and stop
    char mac[6];
    Ar6IpToMac(ip, mac);
    if (MacIsEmpty(mac))
    {
        Ar6MakeRequestForMacFromIp(ip); //The request is only repeated if made after a freeze time - call as often as you want.
        return false;
    }
    
    return true;
}
static bool haveIpAndMac(int type)
{
    if      (type == IPV4) return resolve4(NtpClientQueryServerName, &NtpClientQueryServerIp4);
    else if (type == IPV6) return resolve6(NtpClientQueryServerName,  NtpClientQueryServerIp6);
    else                   return false;
}
void writeRequest(void* pPacket, int* pSize)
{
    struct NtpHeader* pHeader = (struct NtpHeader*)pPacket;
    
    pHeader->Mode             = NTP_CLIENT;
    pHeader->VN               = 3;
    pHeader->LI               = 0;
    pHeader->Stratum          = 0;
    pHeader->Poll             = 0;
    pHeader->Precision        = 0;
    pHeader->RootDelay        = 0;
    pHeader->Dispersion       = 0;
    pHeader->RefIdentifier[0] = 0;
    pHeader->RefIdentifier[1] = 0;
    pHeader->RefIdentifier[2] = 0;
    pHeader->RefIdentifier[3] = 0;
    pHeader->RefTimeStamp     = 0;
    pHeader->OriTimeStamp     = 0;
    pHeader->RecTimeStamp     = 0;
    pHeader->TraTimeStamp     = NetToHost64(ClkTimeToNtpTimeStamp(ClkTimeGet()));

    *pSize = sizeof(struct NtpHeader);
}

int NtpClientQueryPoll(int type, void* pPacket, int* pSize)
{
    if (NtpClientQueryServerName[0]) //An empty name means ntp client is not enabled
    {
        if (intervalCompleteNtp()) //Wait for the time out
        {
            bool isMulticast = NtpClientQueryServerName[0] == '*';
            if (isMulticast || haveIpAndMac(type))
            {
                ClkGovIsReceivingTime = false;
                NtpClientQueryStartInterval(NTP_QUERY_INTERVAL_RETRY);
                writeRequest(pPacket, pSize);
                
                if (isMulticast) return MULTICAST_NTP;
                else             return   UNICAST_NTP;
            }
        }
    }
    return DO_NOTHING;
}