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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nr.c Source File

nr.c

00001 #include <stdint.h>
00002 #include <stdbool.h>
00003 #include <string.h>
00004 
00005 #include      "log.h"
00006 #include  "mstimer.h"
00007 #include      "net.h"
00008 #include      "eth.h"
00009 #include      "mac.h"
00010 #include     "dhcp.h"
00011 #include      "dns.h"
00012 #include "dnsquery.h"
00013 #include "dnslabel.h"
00014 #include     "http.h"
00015 #include  "ip6addr.h"
00016 #include  "ip4addr.h"
00017 #include       "nr.h"
00018 #include   "nrtest.h"
00019 #include      "ndp.h"
00020 #include      "ar6.h"
00021 
00022 bool Nr4Trace = false; //Do not use
00023 bool NrTrace = false;
00024 
00025 #define CACHE_TIMEOUT_MS 3600 * 1000
00026 #define STALE_TIMEOUT_MS 1800 * 1000
00027 #define EMPTY_TIMEOUT_MS  300 * 1000
00028 #define REPLY_TIMEOUT_MS         100
00029 
00030 #define RECORDS_COUNT 50
00031 
00032 #define STATE_EMPTY        0
00033 #define STATE_WANT         1
00034 #define STATE_WAIT_FOR_ETH 2
00035 #define STATE_WAIT_TIMEOUT 3
00036 #define STATE_VALID        4
00037 
00038 #define TODO_NONE              0
00039 #define TODO_NAME_FROM_ADDRESS 1
00040 #define TODO_ADDRESS_FROM_NAME 2
00041 
00042 #define ADDR_TYPE_A    4
00043 #define ADDR_TYPE_AAAA 6
00044 
00045 struct record
00046 {
00047     uint32_t replyMs; //Need this in addition to the ageMs for when refreshing an existing entry
00048     uint32_t ageMs;
00049     union
00050     {
00051         uint32_t A;
00052         uint8_t  AAAA[16];
00053         char     address[16];
00054     };
00055     uint8_t  addrType; //ADDR_TYPE_A (4) or ADDR_TYPE_AAAA (6)
00056     uint8_t  todo;
00057     uint8_t  state;
00058     uint8_t  dnsProtocol;
00059     uint16_t  ipProtocol;
00060     char     name[NR_NAME_MAX_LENGTH];
00061 };
00062 static struct record records[RECORDS_COUNT];
00063 
00064 static void addrClear(const uint8_t addrType, char* ip)
00065 {
00066     switch (addrType)
00067     {
00068         case ADDR_TYPE_A   : *(uint32_t*)ip = 0; break;
00069         case ADDR_TYPE_AAAA: Ip6AddrClear(ip);   break;
00070         default:             LogTimeF("NR - addrClear - Unknown addrType %d\r\n", addrType); break;
00071     }
00072 }
00073 static bool addrIsEmpty(const uint8_t addrType, const char* ip)
00074 {
00075     switch (addrType)
00076     {
00077         case ADDR_TYPE_A   : return *(uint32_t*)ip == 0;
00078         case ADDR_TYPE_AAAA: return Ip6AddrIsEmpty(ip);
00079         default:             return LogTimeF("NR - addrIsEmpty - Unknown addrType %d\r\n", addrType);
00080     }
00081 }
00082 static int addrLog(uint8_t addrType, const char* ip)
00083 {
00084     switch (addrType)
00085     {
00086         case ADDR_TYPE_A   : return Ip4AddrLog(*(uint32_t*)ip);
00087         case ADDR_TYPE_AAAA: return Ip6AddrLog(ip);
00088         default:             return LogTimeF("NR - addrLog - Unknown addrType %d\r\n", addrType);
00089     }
00090 }
00091 
00092 static bool addrIsSame(uint8_t addrType, const char* ipA, const char* ipB)
00093 {
00094     switch (addrType)
00095     {
00096         case ADDR_TYPE_A   : return *(uint32_t*)ipA == *(uint32_t*)ipB;
00097         case ADDR_TYPE_AAAA: return Ip6AddrIsSame(ipA, ipB);
00098         default:             return LogTimeF("NR - addrIsSame - Unknown addrType %d\r\n", addrType);
00099     }
00100 }
00101 
00102 static void addrCopy(uint8_t addrType, char* ipTo, const char* ipFrom)
00103 {
00104     switch (addrType)
00105     {
00106         case ADDR_TYPE_A   : *(uint32_t*)ipTo = *(uint32_t*)ipFrom; break;
00107         case ADDR_TYPE_AAAA: Ip6AddrCopy(ipTo, ipFrom);             break;
00108         default:             LogTimeF("NR - addrCopy - Unknown addrType %d\r\n", addrType); break;
00109     }
00110 }
00111 
00112 static int getExistingAddress(char* address, uint8_t addrType)
00113 {
00114     for (int i = 0; i < RECORDS_COUNT; i++)
00115     {
00116         if (records[i].state == STATE_EMPTY) continue;
00117         if (records[i].addrType != addrType) continue;
00118         if (addrIsSame(addrType, records[i].address, address)) return i;
00119     }
00120     return -1;
00121 }
00122 static int getExistingName(char* name, uint8_t addrType)
00123 {
00124     for (int i = 0; i < RECORDS_COUNT; i++)
00125     {
00126         if (records[i].state == STATE_EMPTY) continue;
00127         if (records[i].addrType != addrType) continue;
00128         if (DnsLabelIsSame(records[i].name, name)) return i;
00129     }
00130     return -1;
00131 }
00132 static int getOldest()
00133 {
00134     int        iOldest = 0;
00135     uint32_t ageOldest = 0;
00136     for (int i = 0; i < RECORDS_COUNT; i++)
00137     {
00138         if (records[i].state == STATE_EMPTY) return i; //Found an empty slot so just return it
00139         uint32_t age = MsTimerCount - records[i].ageMs;
00140         if (age >= ageOldest)
00141         {
00142             ageOldest = age;
00143               iOldest = i;
00144         }
00145     }  
00146     return iOldest;                            //Otherwise return the oldest
00147 }
00148 static void makeRequestForNameFromAddress(uint8_t addrType, void* address )
00149 {
00150     //Don't treat non ips
00151     if (addrIsEmpty(addrType, address)) return;
00152     int i;
00153     
00154     //If a valid record already exists then request an update
00155     i = getExistingAddress(address, addrType);
00156     if (i > -1)
00157     {
00158         if (records[i].state != STATE_VALID) return;
00159         if (records[i].name[0] == 0)
00160         {
00161             if (!MsTimerRelative(records[i].ageMs, EMPTY_TIMEOUT_MS)) return;
00162         }
00163         else
00164         {
00165             if (!MsTimerRelative(records[i].ageMs, STALE_TIMEOUT_MS)) return;
00166         }
00167         if (NrTrace)
00168         {
00169             LogTimeF("NR - record %2d - renew name of ", i);
00170             addrLog(addrType, address);
00171             Log("\r\n");
00172         }
00173         //Leave the address as is
00174         //Leave the name as is
00175         //Leave age as is
00176     }
00177     else
00178     {
00179         //If a record does not exist then find the first empty slot and add the IP and date
00180         i = getOldest();
00181         if (NrTrace)
00182         {
00183             LogTimeF("NR - record %2d - request name of ", i);
00184             addrLog(addrType, address);
00185             Log("\r\n");
00186         }
00187         addrCopy(addrType, records[i].address, address);  //Set the address
00188         records[i].name[0]  = 0;                          //Clear the name
00189         records[i].ageMs    = MsTimerCount;               //Start age
00190     }
00191     records[i].todo        = TODO_NAME_FROM_ADDRESS;
00192     records[i].addrType    = addrType;
00193     records[i].state       = STATE_WANT;
00194     records[i].replyMs     = MsTimerCount;
00195     records[i].ipProtocol  = ETH_NONE;
00196     records[i].dnsProtocol = DNS_PROTOCOL_NONE;
00197 }
00198 static void makeRequestForAddressFromName(char* name, uint8_t addrType)
00199 {
00200     //Don't treat non names
00201     if (!name[0]) return;
00202     int i;
00203         
00204     //If a valid record already exists then request an update
00205     i = getExistingName(name, addrType);
00206     if (i > -1)
00207     {
00208         if (records[i].state != STATE_VALID) return;
00209         if (addrIsEmpty(records[i].addrType, records[i].address))
00210         {
00211             if (!MsTimerRelative(records[i].ageMs, EMPTY_TIMEOUT_MS)) return;
00212         }
00213         else
00214         {
00215             if (!MsTimerRelative(records[i].ageMs, STALE_TIMEOUT_MS)) return;
00216         }
00217         if (NrTrace)
00218         {
00219             if (addrType == ADDR_TYPE_A) LogTimeF("NR - record %2d - renew A of %s\r\n", i, name);
00220             else                         LogTimeF("NR - record %2d - renew AAAA of %s\r\n", i, name);
00221         }
00222         //Leave name as is
00223         //Leave the address as is
00224         //Leave age as is
00225     }
00226     else
00227     {   
00228         //If a record does not exist then find the first empty slot and add the name and date
00229         i = getOldest();
00230         if (NrTrace)
00231         {
00232             if (addrType == ADDR_TYPE_A) LogTimeF("NR - record %2d - request A of %s\r\n", i, name);
00233             else                         LogTimeF("NR - record %2d - request AAAA of %s\r\n", i, name);
00234         }
00235         strncpy(records[i].name, name, NR_NAME_MAX_LENGTH); //Set the name
00236         records[i].name[NR_NAME_MAX_LENGTH - 1] = 0;
00237         addrClear(addrType, records[i].address);            //Clear the address
00238         records[i].ageMs  = MsTimerCount;                   //Start age
00239     }
00240     records[i].todo        = TODO_ADDRESS_FROM_NAME;
00241     records[i].addrType    = addrType;
00242     records[i].state       = STATE_WANT;
00243     records[i].replyMs     = MsTimerCount;
00244     records[i].ipProtocol  = ETH_NONE;
00245     records[i].dnsProtocol = DNS_PROTOCOL_NONE;
00246 }
00247 static void addEntry(uint8_t addrType, void* address, char* name, int dnsProtocol, int ipProtocol)
00248 {
00249 
00250     //Ignore records which do not have both address and name    
00251     if (addrIsEmpty(addrType, address) || name == 0 || name[0] == 0)
00252     {
00253         if (NrTrace) LogTimeF("NR - ignoring invalid entry\r\n");
00254         return;
00255     }
00256     //Ignore records with the name 'UNKNOWN'
00257     if (strcmp(name, "UNKNOWN") == 0) return;
00258     
00259     //Delete any existing records linked to the new entry
00260     for (int i = 0; i < RECORDS_COUNT; i++)
00261     {
00262         if (records[i].state == STATE_EMPTY) continue;
00263         if (records[i].addrType != addrType) continue;
00264         bool sameAddress = addrIsSame(addrType, records[i].address, address);
00265         bool sameName = DnsLabelIsSame(records[i].name, name);
00266         bool noAddress = addrIsEmpty(addrType, records[i].address);
00267         bool requesting = records[i].state != STATE_VALID;
00268         if (sameAddress || (sameName && (noAddress || requesting))) records[i].state = STATE_EMPTY;
00269     }
00270 
00271     //Add the new entry
00272     int i = getOldest();
00273     if (NrTrace)
00274     {
00275         LogTimeF("NR - record %2d - received ", i);
00276         EthProtocolLog(ipProtocol);
00277         Log(" ");
00278         DnsProtocolLog(dnsProtocol);
00279         Log(" ");
00280         addrLog(addrType, address);
00281         Log(" == '");
00282         Log(name);
00283         Log("'\r\n");
00284     }
00285     records[i].todo        = TODO_NONE;
00286     records[i].ageMs       = MsTimerCount;
00287     records[i].addrType    = addrType;
00288     addrCopy(addrType, records[i].address, address);
00289     records[i].dnsProtocol = dnsProtocol;
00290     records[i].ipProtocol  = ipProtocol;
00291     records[i].state       = STATE_VALID;
00292     strncpy(records[i].name, name, NR_NAME_MAX_LENGTH);
00293     records[i].name[NR_NAME_MAX_LENGTH - 1] = 0;
00294 }
00295 static void addressToName(uint8_t addrType, void* address, char* name)
00296 {
00297     for (int i = 0; i < RECORDS_COUNT; i++)
00298     {
00299         if (records[i].state == STATE_EMPTY) continue;
00300         if (addrIsSame(addrType, records[i].address, address))
00301         {
00302             strcpy(name, records[i].name);
00303             return;
00304         }
00305     }
00306     name[0] = 0;
00307 }
00308 static void nameToAddress(char* name, uint8_t addrType, void* address)
00309 {
00310     uint32_t newest = 0xFFFFFFFF;
00311     addrClear(addrType, address);
00312     for (int i = 0; i < RECORDS_COUNT; i++)
00313     {
00314         if (records[i].state == STATE_EMPTY) continue;
00315         if (records[i].addrType != addrType) continue;
00316         if(addrIsEmpty(records[i].addrType, records[i].address)) continue;
00317         if (!DnsLabelIsSame(records[i].name, name)) continue;
00318         uint32_t age = MsTimerCount - records[i].ageMs;
00319         if (age <= newest)
00320         {
00321             newest = age;
00322             addrCopy(addrType, address, records[i].address);
00323         }
00324     }
00325 }
00326 void NrMakeRequestForNameFromAddress6(char*   pAddress) { makeRequestForNameFromAddress(ADDR_TYPE_AAAA, pAddress); }
00327 void NrMakeRequestForNameFromAddress4(uint32_t address) { makeRequestForNameFromAddress(ADDR_TYPE_A,    &address); }
00328 void NrMakeRequestForAddress6FromName(char* name)       { makeRequestForAddressFromName(name, ADDR_TYPE_AAAA); }
00329 void NrMakeRequestForAddress4FromName(char* name)       { makeRequestForAddressFromName(name, ADDR_TYPE_A   ); }
00330 void NrAddAddress6(char*   pAddress, char* name, int dnsProtocol) { addEntry(ADDR_TYPE_AAAA, pAddress, name, dnsProtocol, EthProtocol); }
00331 void NrAddAddress4(uint32_t address, char* name, int dnsProtocol) { addEntry(ADDR_TYPE_A,    &address, name, dnsProtocol, EthProtocol); }
00332 void NrNameToAddress6(char* name,      char* address) { nameToAddress(name, ADDR_TYPE_AAAA, address); }
00333 void NrNameToAddress4(char* name, uint32_t* pAddress) { nameToAddress(name, ADDR_TYPE_A,   pAddress); }
00334 void NrAddress6ToName(char*   pAddress, char* name)   { addressToName(ADDR_TYPE_AAAA, pAddress, name); }
00335 void NrAddress4ToName(uint32_t address, char* name)   { addressToName(ADDR_TYPE_A,    &address, name); }
00336 
00337 static char letterFromStateAndProtocol(uint8_t dnsState, uint8_t dnsProtocol, uint16_t ipProtocol)
00338 {
00339     switch (dnsState)
00340     {
00341         case STATE_WANT:         return '}';
00342         case STATE_WAIT_FOR_ETH: return ']';
00343         case STATE_WAIT_TIMEOUT: return '>';
00344         
00345         case STATE_VALID:
00346             switch (dnsProtocol)
00347             {
00348                 case DNS_PROTOCOL_UDNS:  if (ipProtocol == ETH_IPV4) return 'd' ; else return 'D';
00349                 case DNS_PROTOCOL_MDNS:  if (ipProtocol == ETH_IPV4) return 'm' ; else return 'M';
00350                 case DNS_PROTOCOL_LLMNR: if (ipProtocol == ETH_IPV4) return 'l' ; else return 'L';
00351                 case DNS_PROTOCOL_NONE:  return '-';
00352                 default:                 return '?';
00353             }
00354         default:                         return '~';
00355     }
00356 }
00357 void NrSendAjax()
00358 {
00359     for (int i = 0; i < RECORDS_COUNT; i++)
00360     {
00361         if (records[i].state == STATE_EMPTY) continue;
00362         if (!addrIsEmpty(records[i].addrType, records[i].address) || records[i].name[0])
00363         {
00364             HttpAddByteAsHex(i);
00365             HttpAddChar('\t');
00366             HttpAddInt32AsHex(MsTimerCount - records[i].ageMs);
00367             HttpAddChar('\t');
00368             HttpAddNibbleAsHex(records[i].addrType);
00369             HttpAddChar('\t');
00370             switch (records[i].addrType)
00371             {
00372                 case ADDR_TYPE_A:
00373                 {
00374                     HttpAddInt32AsHex(records[i].A);
00375                     break;
00376                 }
00377                 case ADDR_TYPE_AAAA:
00378                     for (int b = 0; b < 16; b++) HttpAddByteAsHex(records[i].AAAA[b]);
00379                     break;
00380             }
00381             HttpAddChar('\t');
00382             HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].dnsProtocol, records[i].ipProtocol));
00383             HttpAddChar('\t');
00384             HttpAddText(records[i].name);
00385             HttpAddChar('\n');
00386         }
00387     }
00388 }
00389 static void clearCache(struct record* pr)
00390 {
00391     if (MsTimerRelative(pr->ageMs, CACHE_TIMEOUT_MS)) pr->state = STATE_EMPTY;
00392 }
00393 static void queryNameFromIp(struct record* pr)
00394 {
00395     if (addrIsEmpty(pr->addrType, pr->address))
00396     {
00397         LogTimeF("NR - record %2d - queryNameFromIp has no address\r\n", pr - records);
00398         return;
00399     }
00400     if (NrTrace)
00401     {
00402         LogTimeF("NR - record %2d - send ", pr - records);
00403         EthProtocolLog(pr->ipProtocol);
00404         Log(" ");
00405         DnsProtocolLog(pr->dnsProtocol);
00406         Log(" request for name of ");
00407         addrLog(pr->addrType, pr->address);
00408         Log("\r\n");
00409     }
00410     if (pr->addrType == ADDR_TYPE_A) 
00411     {
00412         //uint32_t address4 = addrToIp4(pr->address);
00413         DnsQueryNameFromIp4(pr->A, pr->dnsProtocol, pr->ipProtocol);
00414     }
00415     else
00416     {
00417         DnsQueryNameFromIp6(pr->address, pr->dnsProtocol, pr->ipProtocol);
00418     }
00419 }
00420 static void queryIpFromName(struct record* pr)
00421 {
00422     if (NrTrace)
00423     {
00424         LogTimeF("NR - record %2d - send ", pr - records);
00425         EthProtocolLog(pr->ipProtocol);
00426         Log(" ");
00427         DnsProtocolLog(pr->dnsProtocol);
00428         if (pr->addrType == ADDR_TYPE_A) Log(" request for A of name '");
00429         else                             Log(" request for AAAA of name '");
00430         Log(pr->name);
00431         Log("'\r\n");
00432     }
00433     if (pr->addrType == ADDR_TYPE_A) DnsQueryIp4FromName(pr->name, pr->dnsProtocol, pr->ipProtocol);
00434     else                             DnsQueryIp6FromName(pr->name, pr->dnsProtocol, pr->ipProtocol);
00435 }
00436 static bool getIsExternal(struct record* pr)
00437 {
00438     switch(pr->todo)
00439     {
00440         case TODO_NAME_FROM_ADDRESS:
00441             
00442             if (pr->addrType == ADDR_TYPE_AAAA)
00443             {
00444                 return Ip6AddrIsExternal((char*)pr->AAAA);
00445             }
00446             else
00447             {
00448                 return Ip4AddrIsExternal(pr->A);
00449             }
00450         case TODO_ADDRESS_FROM_NAME:
00451             return DnsLabelIsExternal(pr->name);
00452         default:
00453             LogTimeF("NR - getIsExternal - undefined todo '%d'\r\n", pr->todo);
00454             return false;
00455     }
00456 }
00457 static bool protocolIsAvailable(struct record* pr)
00458 {
00459     bool isExternal = getIsExternal(pr);
00460     switch(pr->dnsProtocol)
00461     {
00462         case DNS_PROTOCOL_MDNS: return !isExternal;
00463         case DNS_PROTOCOL_LLMNR: return !isExternal;
00464         case DNS_PROTOCOL_UDNS:
00465             if (pr->ipProtocol == ETH_IPV6)
00466             {
00467                 if (Ip6AddrIsEmpty(NdpDnsServer)) return false; //No DNS server so not ok
00468                 if (isExternal) return true; //External and have DNS server so ok
00469                 return false; //Internal but have no DHCP6 domain name so not ok
00470             }
00471             else //ETH_IPV4
00472             {
00473                 if (DhcpDnsServerIp == 0) return false; //No DNS server so not ok
00474                 if (isExternal) return true; //External and have DNS server so ok
00475                 return DhcpDomainName[0] != 0; //Internal and have domain name so ok
00476             }
00477         case DNS_PROTOCOL_NONE: return true; //No protocol is valid as it designates 'not found'
00478         default:                return false;
00479     }
00480 }
00481 static void makeNextProtocol(struct record* pr)
00482 {
00483     //If current protocol is empty or unknown then return with the first.
00484     switch (pr->ipProtocol)
00485     {
00486         case ETH_IPV6: break;
00487         case ETH_IPV4: break;
00488         default:
00489             pr->ipProtocol  = ETH_IPV6;
00490             pr->dnsProtocol = DNS_PROTOCOL_MDNS;
00491             return;
00492     }
00493     switch (pr->dnsProtocol)
00494     {
00495         case DNS_PROTOCOL_MDNS:  break;
00496         case DNS_PROTOCOL_LLMNR: break;
00497         case DNS_PROTOCOL_UDNS:  break;
00498         default:
00499             pr->ipProtocol  = ETH_IPV6;
00500             pr->dnsProtocol = DNS_PROTOCOL_MDNS;
00501             return;
00502 
00503     }
00504     switch(pr->dnsProtocol)
00505     {
00506         case DNS_PROTOCOL_MDNS: 
00507             if (pr->ipProtocol == ETH_IPV6)
00508             {
00509                 pr->ipProtocol = ETH_IPV4;
00510             }
00511             else
00512             {
00513                 pr->ipProtocol = ETH_IPV6;
00514                 pr->dnsProtocol = DNS_PROTOCOL_LLMNR;
00515             }
00516             break;
00517         case DNS_PROTOCOL_LLMNR:
00518             if (pr->ipProtocol == ETH_IPV6)
00519             {
00520                 pr->ipProtocol = ETH_IPV4;
00521             }
00522             else
00523             {
00524                 pr->ipProtocol = ETH_IPV6;
00525                 pr->dnsProtocol = DNS_PROTOCOL_UDNS;
00526             }
00527             break;
00528         case DNS_PROTOCOL_UDNS:
00529             if (pr->ipProtocol == ETH_IPV6)
00530             {
00531                 pr->ipProtocol = ETH_IPV4;
00532             }
00533             else
00534             {
00535                 pr->ipProtocol  = ETH_NONE;
00536                 pr->dnsProtocol = DNS_PROTOCOL_NONE;
00537             }
00538             break;
00539     }
00540 }
00541 
00542 static void sendRequest(struct record* pr)
00543 {
00544     //if (DnsQueryIsBusy) return;
00545     
00546     switch (pr->state)
00547     {
00548         case STATE_WANT:
00549             makeNextProtocol(pr);
00550             while (!protocolIsAvailable(pr)) makeNextProtocol(pr);
00551             if (!pr->dnsProtocol || !pr->ipProtocol) //No more protocols to try so resolution has failed
00552             {
00553                 if (pr->todo == TODO_NAME_FROM_ADDRESS)
00554                 {
00555                     if (NrTrace)
00556                     {
00557                         LogTimeF("NR - record %2d - request for name of ", pr - records);
00558                         addrLog(pr->addrType, pr->address);
00559                         Log(" has timed out\r\n");
00560                     }
00561                     pr->name[0] = 0;
00562                 }
00563                 if (pr->todo == TODO_ADDRESS_FROM_NAME)
00564                 {
00565                     if (NrTrace)
00566                     {
00567                         LogTimeF("NR - record %2d - request for address of '", pr - records);
00568                         Log(pr->name);
00569                         Log("' has timed out\r\n");
00570                         Log("\r\n");
00571                     }
00572                     addrClear(pr->addrType, pr->address);
00573                 }
00574                 pr->todo   = TODO_NONE;
00575                 pr->state  = STATE_VALID;
00576                 pr->ageMs  = MsTimerCount;
00577             }
00578             else
00579             {
00580                 pr->state  = STATE_WAIT_FOR_ETH;
00581             }
00582             break;
00583         case STATE_WAIT_FOR_ETH:
00584             if (!DnsQueryIsBusy)
00585             {   
00586                 switch (pr->todo)
00587                 {
00588                     case TODO_NAME_FROM_ADDRESS: queryNameFromIp(pr); break;
00589                     case TODO_ADDRESS_FROM_NAME: queryIpFromName(pr); break;
00590                 }
00591                 pr->state = STATE_WAIT_TIMEOUT;
00592                 pr->replyMs = MsTimerCount;
00593             }
00594             break;
00595         case STATE_WAIT_TIMEOUT:
00596             if (MsTimerRelative(pr->replyMs, REPLY_TIMEOUT_MS))
00597             {
00598                 pr->state = STATE_WANT;
00599             }
00600             break;
00601         default:
00602             break;
00603     }
00604 }
00605 void NrMain()
00606 {
00607     static int i = -1;
00608     i++;
00609     if (i >= RECORDS_COUNT) i = 0;
00610     
00611     struct record* pr = &records[i];
00612     
00613     clearCache  (pr);
00614     sendRequest (pr);
00615     
00616     NrTestMain();
00617 }
00618 void NrInit()
00619 {
00620     for (int i = 0; i < RECORDS_COUNT; i++) records[i].state = STATE_EMPTY;
00621 }