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
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 }
Generated on Tue Jul 12 2022 18:53:40 by 1.7.2