Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
Diff: eth/nr4.c
- Revision:
- 61:aad055f1b0d1
- Parent:
- 60:1d8c7a1e7483
- Child:
- 65:37acccf2752f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eth/nr4.c Thu Jan 11 17:38:21 2018 +0000 @@ -0,0 +1,375 @@ +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include "log.h" +#include "clock.h" +#include "net.h" +#include "mac.h" +#include "ip4addr.h" +#include "dns.h" +#include "dhcp.h" +#include "dnsquery.h" +#include "http.h" + +bool Nr4Trace = false; + +#define NAME_MAX_LENGTH 20 +#define CACHE_TIMEOUT 3600 +#define FREEZE_TIMEOUT 1800 +#define REPLY_TIMEOUT 2 + +#define RECORDS_COUNT 20 + +#define STATE_EMPTY 0 +#define STATE_WANT 1 +#define STATE_SENT 2 +#define STATE_VALID 3 + +#define TODO_NONE 0 +#define TODO_NAME_FROM_IP 1 +#define TODO_IP_FROM_NAME 2 + +static uint32_t elapsed = 0; +struct record +{ + uint32_t elapsed; + uint32_t ip; + uint8_t todo; + uint8_t state; + uint8_t protocol; + char name[NAME_MAX_LENGTH]; +}; +static struct record records[RECORDS_COUNT]; + +static int getExistingIp(uint32_t ip) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) continue; + if (records[i].ip == ip) return i; + } + return -1; +} +static int getExistingName(char* name) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) continue; + if (DnsHostNamesEquate(records[i].name, name)) return i; + } + return -1; +} +static int getNameOnly(char* name) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) continue; + if (records[i].ip) continue; + if (DnsHostNamesEquate(records[i].name, name)) return i; + } + return -1; +} +static int getOldest() +{ + int iN = 0; + uint32_t tN = 0xFFFFFFFF; + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) return i; //Found an empty slot so just return it + if (records[i].elapsed < tN) + { + tN = records[i].elapsed; + iN = i; + } + } + return iN; //Otherwise return the oldest +} +void Nr4MakeRequestForNameFromIp(uint32_t ip) +{ + //Don't treat non ips + if (!ip) return; + int i; + + //If a record already exists then request an update + i = getExistingIp(ip); + if (i > -1) + { + if (elapsed < records[i].elapsed + FREEZE_TIMEOUT) return; + if (Nr4Trace) + { + LogTimeF("NR - renew name of "); + Ip4AddressLog(ip); + Log("\r\n"); + } + records[i].todo = TODO_NAME_FROM_IP; + records[i].state = STATE_WANT; + records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); + records[i].elapsed = elapsed; + return; + } + + //If a record does not exist then find the first empty slot and add the IP and date + if (Nr4Trace) + { + LogTimeF("NR - request name of "); + Ip4AddressLog(ip); + Log("\r\n"); + } + i = getOldest(); + records[i].ip = ip; + records[i].todo = TODO_NAME_FROM_IP; + records[i].state = STATE_WANT; + records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); + records[i].elapsed = elapsed; + records[i].name[0] = 0; +} +void Nr4MakeRequestForIpFromName(char* name) +{ + //Don't treat non names + if (!name[0]) return; + int i; + + //If a record already exists then request an update + i = getExistingName(name); + if (i > -1) + { + if (elapsed < records[i].elapsed + FREEZE_TIMEOUT) return; + if (Nr4Trace) + { + LogTimeF("NR - renew IPv4 of %s\r\n", name); + } + records[i].todo = TODO_IP_FROM_NAME; + records[i].state = STATE_WANT; + records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); + records[i].elapsed = elapsed; + return; + } + + //If a record does not exist then find the first empty slot and add the name and date + if (Nr4Trace) + { + LogTimeF("NR - request IPv4 of %s\r\n", name); + } + i = getOldest(); + records[i].ip = 0; + records[i].todo = TODO_IP_FROM_NAME; + records[i].state = STATE_WANT; + records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); + records[i].elapsed = elapsed; + strncpy(records[i].name, name, NAME_MAX_LENGTH); + records[i].name[NAME_MAX_LENGTH - 1] = 0; +} +static void addIpRecord(int i, uint32_t ip, char* name, int protocol) +{ + records[i].todo = TODO_NONE; + records[i].elapsed = elapsed; + 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 Nr4AddIpRecord(uint32_t ip, char* name, int protocol) +{ + int i; + + //Get existing ip and, if found, add it then clear any name only entries + i = getExistingIp(ip); + if (i >= 0) + { + if (Nr4Trace) + { + if (DnsHostNamesEquate(name, records[i].name)) LogTimeF("NR - confirm existing "); + else LogTimeF("NR - replace name for existing ip "); + Ip4AddressLog(ip); + Log(" == '"); + Log(name); + Log("'\r\n"); + } + addIpRecord(i, ip, name, protocol); + + i = getNameOnly(name); + if (i >= 0) + { + if (Nr4Trace) LogTimeF("NR - clear name '%s' with no ip\r\n", name); + records[i].state = STATE_EMPTY; + } + return; + } + + //Get name only entry and, if found, add it + i = getNameOnly(name); + if (i >= 0) + { + if (Nr4Trace) + { + LogTimeF("NR - add ip for name "); + Ip4AddressLog(ip); + Log(" == '"); + Log(name); + Log("'\r\n"); + } + addIpRecord(i, ip, name, protocol); + return; + } + + //No other entry exists so just add it to the next available space + i = getOldest(); + if (Nr4Trace) + { + LogTimeF("NR - add ip for name "); + Ip4AddressLog(ip); + Log(" == '"); + Log(name); + Log("'\r\n"); + } + addIpRecord(i, ip, name, protocol); +} +void Nr4IpToName(uint32_t ip, char* name) +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) continue; + if (records[i].ip == ip) + { + strcpy(name, records[i].name); + return; + } + } + name[0] = 0; +} +void Nr4NameToIp(char* name, uint32_t* pIp) +{ + int newest = 0; + *pIp = 0; + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) continue; + if (!records[i].ip) continue; + if (!DnsHostNamesEquate(records[i].name, name)) continue; + if (records[i].elapsed > newest) + { + newest = records[i].elapsed; + *pIp = records[i].ip; + } + } +} +static char letterFromStateAndProtocol(uint8_t dnsState, uint8_t protocol) +{ + switch (dnsState) + { + case STATE_SENT: + case STATE_WANT: return '>'; + + case STATE_VALID: + switch (protocol) + { + case DNS_PROTOCOL_UDNS: return 'd'; + case DNS_PROTOCOL_MDNS: return 'm'; + case DNS_PROTOCOL_LLMNR: return 'l'; + case DNS_PROTOCOL_NONE: return '-'; + default: return '?'; + } + default: return '~'; + } +} +void Nr4SendHttp() +{ + for (int i = 0; i < RECORDS_COUNT; i++) + { + if (records[i].state == STATE_EMPTY) continue; + if (records[i].ip || records[i].name[0]) + { + HttpAddF("%4u ", (elapsed - records[i].elapsed) / 60); + + int ipLen = Ip4AddressHttp(records[i].ip); + HttpFillChar(' ', 40 - ipLen); + + HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].protocol)); + + HttpAddChar(' '); + + HttpAddText(records[i].name); + + HttpAddChar('\r'); + HttpAddChar('\n'); + } + } +} +static void clearCache(struct record* pr) +{ + if (elapsed > pr->elapsed + CACHE_TIMEOUT) pr->state = STATE_EMPTY; +} +static void nextProtocol(struct record* pr) +{ + if (pr->state == STATE_SENT && elapsed > pr->elapsed + REPLY_TIMEOUT && pr->protocol) + { + pr->protocol = DnsGetNextProtocol4(pr->protocol); + if (pr->protocol) + { + pr->state = STATE_WANT; + } + else + { + if (pr->todo == TODO_NAME_FROM_IP) pr->name[0] = 0; + if (pr->todo == TODO_IP_FROM_NAME) pr->ip = 0; + pr->state = STATE_VALID; + } + pr->elapsed = elapsed; + } +} +static void queryNameFromIp(struct record* pr) +{ + if (Nr4Trace) + { + LogTime("NR - send "); + DnsProtocolLog(pr->protocol); + Log(" request for name from IP4 "); + Ip4AddressLog(pr->ip); + Log("\r\n"); + } + DnsQueryNameFromIp4(pr->ip, pr->protocol); +} +static void queryIpFromName(struct record* pr) +{ + if (Nr4Trace) + { + LogTime("NR - send "); + DnsProtocolLog(pr->protocol); + Log(" request for IP4 from name '"); + Log(pr->name); + Log("'\r\n"); + } + DnsQueryIp4FromName(pr->name, pr->protocol); +} +static void sendRequest(struct record* pr) +{ + if ( DnsQueryIsBusy ) return; + if ( pr->state != STATE_WANT) return; + if (!pr->protocol ) return; + + if (pr->todo == TODO_NAME_FROM_IP) queryNameFromIp(pr); + if (pr->todo == TODO_IP_FROM_NAME) queryIpFromName(pr); + + pr->state = STATE_SENT; + pr->elapsed = elapsed; +} +void Nr4Main() +{ + static int i = -1; + i++; + if (i >= RECORDS_COUNT) i = 0; + + struct record* pr = &records[i]; + + clearCache (pr); + nextProtocol(pr); + sendRequest (pr); + + if (ClockTicked) elapsed++; +} +void Nr4Init() +{ + for (int i = 0; i < RECORDS_COUNT; i++) records[i].state = STATE_EMPTY; +}