Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Revision:
171:f708d6776752
Parent:
170:96c637dc3f52
diff -r 96c637dc3f52 -r f708d6776752 resolve/nr6.c
--- a/resolve/nr6.c	Wed Dec 09 18:11:05 2020 +0000
+++ b/resolve/nr6.c	Sat Dec 12 20:10:02 2020 +0000
@@ -18,8 +18,8 @@
 #define NAME_MAX_LENGTH     20
 #define CACHE_TIMEOUT_MS 3600 * 1000
 #define STALE_TIMEOUT_MS 1800 * 1000
-#define EMPTY_TIMEOUT_MS    5 * 1000
-#define REPLY_TIMEOUT_MS    1 * 1000
+#define EMPTY_TIMEOUT_MS  300 * 1000
+#define REPLY_TIMEOUT_MS         100
 
 #define RECORDS_COUNT 20
 
@@ -28,17 +28,20 @@
 #define STATE_SENT  2
 #define STATE_VALID 3
 
-#define TODO_NONE         0
-#define TODO_NAME_FROM_IP 1
-#define TODO_IP_FROM_NAME 2
+#define TODO_NONE          0
+#define TODO_NAME_FROM_IP  1
+#define TODO_IP4_FROM_NAME 2
+#define TODO_IP6_FROM_NAME 3
 
 struct record
 {
-    uint32_t elapsed;
+    uint32_t replyMs;
+    uint32_t ageMs;
     char     ip[16];
     uint8_t  todo;
     uint8_t  state;
-    uint8_t  protocol;
+    uint8_t  dnsProtocol;
+    uint8_t   ipProtocol;
     char     name[NAME_MAX_LENGTH];
 };
 static struct record records[RECORDS_COUNT];
@@ -88,7 +91,7 @@
     for (int i = 0; i < RECORDS_COUNT; i++)
     {
         if (records[i].state == STATE_EMPTY) return i; //Found an empty slot so just return it
-        uint32_t age = MsTimerCount - records[i].elapsed;
+        uint32_t age = MsTimerCount - records[i].ageMs;
         if (age >= ageOldest)
         {
             ageOldest = age;
@@ -97,7 +100,7 @@
     }  
     return iOldest;                            //Otherwise return the oldest
 }
-void Nr6MakeRequestForNameFromIp(char* ip)
+static void makeRequestForNameFromIp(char* ip)
 {
     //Don't treat non ips
     if (!ip[0]) return;
@@ -107,13 +110,14 @@
     i = getExistingIp(ip);
     if (i > -1)
     {
+        if (records[i].state == STATE_WANT || records[i].state == STATE_SENT) return;
         if (records[i].name[0] == 0)
         {
-            if (!MsTimerRelative(records[i].elapsed, EMPTY_TIMEOUT_MS)) return;
+            if (!MsTimerRelative(records[i].ageMs, EMPTY_TIMEOUT_MS)) return;
         }
         else
         {
-            if (!MsTimerRelative(records[i].elapsed, STALE_TIMEOUT_MS)) return;
+            if (!MsTimerRelative(records[i].ageMs, STALE_TIMEOUT_MS)) return;
         }
         if (Nr6Trace)
         {
@@ -121,29 +125,29 @@
             Ip6AddressLog(ip);
             Log("\r\n");
         }
-        records[i].todo     = TODO_NAME_FROM_IP;
-        records[i].state    = STATE_WANT;
-        records[i].protocol = DnsGetNextProtocol(DNS_PROTOCOL_NONE);
-        records[i].elapsed  = MsTimerCount;
-        return;
+        //Leave the ip as is
+        //Leave the name as is
+        //Leave age as is
     }
-    
-    //If a record does not exist then find the first empty slot and add the IP and date
-    if (Nr6Trace)
+    else
     {
-        LogTimeF("NR - request name of ");
-        Ip6AddressLog(ip);
-        Log("\r\n");
+        //If a record does not exist then find the first empty slot and add the IP and date
+        if (Nr6Trace)
+        {
+            LogTimeF("NR - request name of ");
+            Ip6AddressLog(ip);
+            Log("\r\n");
+        }
+        i = getOldest();
+        Ip6AddressCopy(records[i].ip, ip);  //Set the ip
+        records[i].name[0]  = 0;            //Clear the name
+        records[i].ageMs    = MsTimerCount; //Start age
     }
-    i = getOldest();
-    Ip6AddressCopy(records[i].ip, ip);
-    records[i].todo     = TODO_NAME_FROM_IP;
-    records[i].state    = STATE_WANT;
-    records[i].protocol = DnsGetNextProtocol(DNS_PROTOCOL_NONE);
-    records[i].elapsed  = MsTimerCount;
-    records[i].name[0]  = 0;
+    records[i].todo        = TODO_NAME_FROM_IP;
+    records[i].state       = STATE_WANT;
+    records[i].dnsProtocol = DnsGetNextProtocol(DNS_PROTOCOL_NONE);
 }
-void Nr6MakeRequestForIpFromName(char* name)
+static void makeRequestForIpFromName(char* name, int todo)
 {
     //Don't treat non names
     if (!name[0]) return;
@@ -153,57 +157,71 @@
     i = getExistingName(name);
     if (i > -1)
     {
+        if (records[i].state == STATE_WANT || records[i].state == STATE_SENT) return;
         if (Ip6AddressIsEmpty(records[i].ip))
         {
-            if (!MsTimerRelative(records[i].elapsed, EMPTY_TIMEOUT_MS)) return;
+            if (!MsTimerRelative(records[i].ageMs, EMPTY_TIMEOUT_MS)) return;
         }
         else
         {
-            if (!MsTimerRelative(records[i].elapsed, STALE_TIMEOUT_MS)) return;
+            if (!MsTimerRelative(records[i].ageMs, STALE_TIMEOUT_MS)) return;
         }
         if (Nr6Trace)
         {
             LogTimeF("NR - renew IPv6 of %s\r\n", name);
         }
-        records[i].todo     = TODO_IP_FROM_NAME;
-        records[i].state    = STATE_WANT;
-        records[i].protocol = DnsGetNextProtocol(DNS_PROTOCOL_NONE);
-        records[i].elapsed  = MsTimerCount;
-        return;
+        //Leave name as is
+        //Leave the ip as is
+        //Leave age as is
     }
-    
-    //If a record does not exist then find the first empty slot and add the name and date
-    if (Nr6Trace)
-    {
-        LogTimeF("NR - request IPv6 of %s\r\n", name);
+    else
+    {   
+        //If a record does not exist then find the first empty slot and add the name and date
+        if (Nr6Trace)
+        {
+            LogTimeF("NR - request IPv6 of %s\r\n", name);
+        }
+        i = getOldest();
+        strncpy(records[i].name, name, NAME_MAX_LENGTH); //Set the name
+        records[i].name[NAME_MAX_LENGTH - 1] = 0;
+        Ip6AddressClear(records[i].ip);                  //Clear the ip
+        records[i].ageMs  = MsTimerCount;                //Start age
     }
-    i = getOldest();
-    records[i].ip[0]    = 0;
-    records[i].todo     = TODO_IP_FROM_NAME;
-    records[i].state    = STATE_WANT;
-    records[i].protocol = DnsGetNextProtocol(DNS_PROTOCOL_NONE);
-    records[i].elapsed  = MsTimerCount;
+    records[i].todo        = todo;
+    records[i].state       = STATE_WANT;
+    records[i].dnsProtocol = DnsGetNextProtocol(DNS_PROTOCOL_NONE);
+}
+static void updateIpRecord(int i, char* ip, char* name, int dnsProtocol)
+{
+    records[i].todo        = TODO_NONE;
+    records[i].ageMs       = MsTimerCount;
+    Ip6AddressCopy(records[i].ip, ip);
+    records[i].dnsProtocol = dnsProtocol;
+    records[i].state       = STATE_VALID;
     strncpy(records[i].name, name, NAME_MAX_LENGTH);
     records[i].name[NAME_MAX_LENGTH - 1] = 0;
 }
-static void addIpRecord(int i, char* ip, char* name, int protocol)
+void addIpRecord(char* ip, char* name, int dnsProtocol)
 {
-    records[i].todo     = TODO_NONE;
-    records[i].elapsed  = MsTimerCount;
-    Ip6AddressCopy(records[i].ip, ip);
-    records[i].protocol = protocol;
-    records[i].state    = STATE_VALID;
-    strncpy(records[i].name, name, NAME_MAX_LENGTH);
-    records[i].name[NAME_MAX_LENGTH - 1] = 0;
-}
-void Nr6AddIpRecord(char* ip, char* name, int protocol)
-{
+    /*
+    A number of situations may need to be handled:
+    - An existing ip with the same name         ; the usual situation                             : just reset the elapsed time and return
+    - An existing ip with no or a different name; usual if we are resolving an ip                 : add or update the ip of this record
+    - Same name with an empty ip                ; usual if we are resolving a name                : add the ip to this record
+    - Same name with another ip                 ; normal situation                                : do nothing
+    - No existing ip or name                    ; usual if another device has done a reolution    : add a new record and return
+    
+    Quite often we will simultaneously attempt to resolve both the name and the ip of the same device.
+    When this happens there will be two entriesone with the ame and an empty ip; the othert with the ip but and an empty name.
+    In this case we first add the name to the existing ip but also check for the name with an empty ip and delete it.
+    */
+    
     int i;
     
     //Print what is being handled
     if (Nr6Trace)
     {
-        LogTimeF("NR - received response ");
+        LogTimeF("NR - received ");
         Ip6AddressLog(ip);
         Log(" == '");
         Log(name);
@@ -213,7 +231,7 @@
     //Ignore records which do not have both ip and name    
     if (Ip6AddressIsEmpty(ip) || name == 0 || name[0] == 0)
     {
-        if (Nr6Trace) LogTimeF("NR - ignoring unresolved response\r\n");
+        if (Nr6Trace) LogTimeF("NR - ignoring invalid entry\r\n");
         return;
     }
     
@@ -225,24 +243,14 @@
         {
             if (DnsLabelIsSame(name, records[i].name))
             {
-                LogTimeF("NR record %d - confirm existing name for ", i);
-                Ip6AddressLog(ip);
-                Log(" is '");
-                Log(name);
-                Log("'\r\n");
+                LogTimeF("NR record %d - refresh existing entry\r\n", i);
             }
             else
             {
-                LogTimeF("NR record %d - update name for ip ", i);
-                Ip6AddressLog(ip);
-                Log(" from '");
-                Log(records[i].name);
-                Log("' to '");
-                Log(name);
-                Log("'\r\n");
+                LogTimeF("NR record %d - update entry name from '%s' to '%s'\r\n", i, records[i].name, name);
             }
         }
-        addIpRecord(i, ip, name, protocol);
+        updateIpRecord(i, ip, name, dnsProtocol);
         
         i = getNameOnly(name);
         if (i >= 0)
@@ -259,15 +267,11 @@
     {
         if (Nr6Trace)
         {
-            LogTimeF("NR record %d - update ip for name", i);
-            Log(name);
-            Log(" from ");
+            LogTimeF("NR record %d - add ip ", i);
             Ip6AddressLog(ip);
-            Log(" to ");
-            Ip6AddressLog(records[i].ip);
             Log("\r\n");
         }
-        addIpRecord(i, ip, name, protocol);
+        updateIpRecord(i, ip, name, dnsProtocol);
         return;
     }
     
@@ -275,15 +279,11 @@
     i = getOldest();
     if (Nr6Trace)
     {
-        LogTimeF("NR record %d - add entry for ", i);
-        Ip6AddressLog(ip);
-        Log(" == '");
-        Log(name);
-        Log("'\r\n");
+        LogTimeF("NR record %d - add entry\r\n", i);
     }
-    addIpRecord(i, ip, name, protocol);
+    updateIpRecord(i, ip, name, dnsProtocol);
 }
-void Nr6IpToName(char* ip, char* name)
+static void ipToName(char* ip, char* name)
 {
     for (int i = 0; i < RECORDS_COUNT; i++)
     {
@@ -296,7 +296,7 @@
     }
     name[0] = 0;
 }
-void Nr6NameToIp(char* name, char* ip)
+static void nameToIp(char* name, char* ip)
 {
     uint32_t newest = 0xFFFFFFFF;
     Ip6AddressClear(ip);
@@ -305,7 +305,7 @@
         if (records[i].state == STATE_EMPTY) continue;
         if(Ip6AddressIsEmpty(records[i].ip)) continue;
         if (!DnsLabelIsSame(records[i].name, name)) continue;
-        uint32_t age = MsTimerCount - records[i].elapsed;
+        uint32_t age = MsTimerCount - records[i].ageMs;
         if (age <= newest)
         {
             newest = age;
@@ -313,17 +313,55 @@
         }
     }
 }
-bool Nr6HaveIpForName(char* name)
+void Nr6MakeRequestForNameFromIp(char* ip)
+{
+    makeRequestForNameFromIp(ip);
+}
+void Nr4MakeRequestForNameFromIp(uint32_t ip4)
+{
+    char ip6[16];
+    Ip6AddressFromIp4(ip6, ip4);
+    makeRequestForNameFromIp(ip6);
+}
+void Nr6MakeRequestForIpFromName(char* name)
+{
+    makeRequestForIpFromName(name, TODO_IP6_FROM_NAME);
+}
+void Nr4MakeRequestForIpFromName(char* name)
+{
+    makeRequestForIpFromName(name, TODO_IP4_FROM_NAME);
+}
+void Nr6AddIpRecord(char* ip, char* name, int dnsProtocol)
+{
+    addIpRecord(ip, name, dnsProtocol);
+}
+void Nr4AddIpRecord(uint32_t ip4, char* name, int dnsProtocol)
 {
-    for (int i = 0; i < RECORDS_COUNT; i++)
-    {
-        if (records[i].state == STATE_EMPTY) continue;
-        if(Ip6AddressIsEmpty(records[i].ip)) continue;
-        if (!DnsLabelIsSame(records[i].name, name)) return true;
-    }
-    return false;
+    char ip6[16];
+    Ip6AddressFromIp4(ip6, ip4);
+    addIpRecord(ip6, name, dnsProtocol);
+}
+void Nr6NameToIp(char* name, char* ip)
+{
+    nameToIp(name, ip);
 }
-static char letterFromStateAndProtocol(uint8_t dnsState, uint8_t protocol)
+void Nr4NameToIp(char* name, uint32_t* pIp)
+{
+    char ip6[16];
+    nameToIp(name, ip6);
+    *pIp = Ip6AddressToIp4(ip6);
+}
+void Nr6IpToName(char* ip, char* name)
+{
+    ipToName(ip, name);
+}
+void Nr4IpToName(uint32_t ip4, char* name)
+{
+    char ip6[16];
+    Ip6AddressFromIp4(ip6, ip4);
+    ipToName(ip6, name);
+}
+static char letterFromStateAndProtocol(uint8_t dnsState, uint8_t dnsProtocol)
 {
     switch (dnsState)
     {
@@ -331,7 +369,7 @@
         case STATE_SENT:                 return '>';
         
         case STATE_VALID:
-            switch (protocol)
+            switch (dnsProtocol)
             {
                 case DNS_PROTOCOL_UDNS:  return 'd';
                 case DNS_PROTOCOL_MDNS:  return 'm';
@@ -349,12 +387,13 @@
         if (records[i].state == STATE_EMPTY) continue;
         if (!Ip6AddressIsEmpty(records[i].ip) || records[i].name[0])
         {
-            HttpAddF("%4u ", (MsTimerCount - records[i].elapsed) / 1000 / 60);
+            HttpAddF("%4u ", (MsTimerCount - records[i].ageMs) / 1000 / 60);
             
-            int ipLen = Ip6AddressHttp(records[i].ip);
+            int ipLen;
+            ipLen = Ip6AddressHttp(records[i].ip);
             HttpAddFillChar(' ', 40 - ipLen);
 
-            HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].protocol));
+            HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].dnsProtocol));
             
             HttpAddChar(' ');
             
@@ -374,11 +413,11 @@
         {
             HttpAddByteAsHex(i);
             HttpAddChar('\t');
-            HttpAddInt32AsHex(MsTimerCount - records[i].elapsed);
+            HttpAddInt32AsHex(MsTimerCount - records[i].ageMs);
             HttpAddChar('\t');
             for (int b = 0; b < 16; b++) HttpAddByteAsHex(records[i].ip[b]);
             HttpAddChar('\t');
-            HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].protocol));
+            HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].dnsProtocol));
             HttpAddChar('\t');
             HttpAddText(records[i].name);
             HttpAddChar('\n');
@@ -387,24 +426,26 @@
 }
 static void clearCache(struct record* pr)
 {
-    if (MsTimerRelative(pr->elapsed, CACHE_TIMEOUT_MS)) pr->state = STATE_EMPTY;
+    if (MsTimerRelative(pr->ageMs, CACHE_TIMEOUT_MS)) pr->state = STATE_EMPTY;
 }
 static void nextProtocol(struct record* pr)
 {
-    if (pr->state == STATE_SENT && MsTimerRelative(pr->elapsed, REPLY_TIMEOUT_MS) && pr->protocol)
+    if (pr->state == STATE_SENT && MsTimerRelative(pr->replyMs, REPLY_TIMEOUT_MS) && pr->dnsProtocol)
     {
-        pr->protocol = DnsGetNextProtocol(pr->protocol);
-        if (pr->protocol)
+        pr->dnsProtocol = DnsGetNextProtocol(pr->dnsProtocol);
+        if (pr->dnsProtocol)
         {
             pr->state = STATE_WANT;
         }
-        else
+        else //We have tried everything and resolution has failed
         {
             if (pr->todo == TODO_NAME_FROM_IP) pr->name[0] = 0;
-            if (pr->todo == TODO_IP_FROM_NAME) Ip6AddressClear(pr->ip);
+            if (pr->todo == TODO_IP4_FROM_NAME || pr->todo == TODO_IP6_FROM_NAME) Ip6AddressClear(pr->ip);
+            pr->todo   = TODO_NONE;
             pr->state  = STATE_VALID;
+            pr->ageMs  = MsTimerCount;
         }
-        pr->elapsed = MsTimerCount;
+        pr->replyMs = MsTimerCount;
     }
 }
 static void queryNameFromIp(struct record* pr)
@@ -412,36 +453,48 @@
     if (Nr6Trace)
     {
         LogTime("NR - send ");
-        DnsProtocolLog(pr->protocol);
-        Log(" request for name from IP6 ");
+        DnsProtocolLog(pr->dnsProtocol);
+        if (Ip6AddrIsIp4(pr->ip)) Log(" request for name from IP4 ");
+        else                      Log(" request for name from IP6 ");
         Ip6AddressLog(pr->ip);
         Log("\r\n");
     }
-    DnsQueryNameFromIp6(pr->ip, pr->protocol);
+    if (Ip6AddrIsIp4(pr->ip)) 
+    {
+        uint32_t ip4 = Ip6AddressToIp4(pr->ip);
+        DnsQueryNameFromIp4(ip4, pr->dnsProtocol, pr->ipProtocol);
+    }
+    else
+    {
+        DnsQueryNameFromIp6(pr->ip, pr->dnsProtocol, pr->ipProtocol);
+    }
 }
-static void queryIpFromName(struct record* pr)
+static void queryIpFromName(struct record* pr, int todo)
 {
     if (Nr6Trace)
     {
         LogTime("NR - send ");
-        DnsProtocolLog(pr->protocol);
-        Log(" request for IP6 from name '");
+        DnsProtocolLog(pr->dnsProtocol);
+        if (todo == TODO_IP4_FROM_NAME) Log(" request for IP4 from name '");
+        else                            Log(" request for IP6 from name '");
         Log(pr->name);
         Log("'\r\n");
     }
-    DnsQueryIp6FromName(pr->name, pr->protocol);
+    if (todo == TODO_IP4_FROM_NAME) DnsQueryIp4FromName(pr->name, pr->dnsProtocol, pr->ipProtocol);
+    else                            DnsQueryIp6FromName(pr->name, pr->dnsProtocol, pr->ipProtocol);
 }
 static void sendRequest(struct record* pr)
 {
-    if ( DnsQueryIsBusy         ) return;
-    if ( pr->state != STATE_WANT) return;
-    if (!pr->protocol           ) return;
+    if ( DnsQueryIsBusy            ) return;
+    if ( pr->state != STATE_WANT   ) return;
+    if (!pr->dnsProtocol           ) return;
     
-    if (pr->todo == TODO_NAME_FROM_IP) queryNameFromIp(pr);
-    if (pr->todo == TODO_IP_FROM_NAME) queryIpFromName(pr);
+    if (pr->todo == TODO_NAME_FROM_IP ) queryNameFromIp(pr);
+    if (pr->todo == TODO_IP4_FROM_NAME) queryIpFromName(pr, TODO_IP4_FROM_NAME);
+    if (pr->todo == TODO_IP6_FROM_NAME) queryIpFromName(pr, TODO_IP6_FROM_NAME);
     
     pr->state = STATE_SENT;
-    pr->elapsed = MsTimerCount;
+    pr->replyMs = MsTimerCount;
 }
 void Nr6Main()
 {