1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-22 23:56:13 +01:00

tidy up values into name, serviceName, serviceProto and packet generation

This commit is contained in:
Harald Barth 2024-11-10 19:48:52 +01:00
parent 9a6e1707e7
commit 0a96320fd0
3 changed files with 84 additions and 44 deletions

View File

@ -2,15 +2,49 @@
#include <Arduino.h> #include <Arduino.h>
#include "EthernetInterface.h" #include "EthernetInterface.h"
#include "EXmDNS.h" #include "EXmDNS.h"
#include "DIAG.h"
// fixed values for mDNS
static IPAddress mdnsMulticastIPAddr = IPAddress(224, 0, 0, 251); static IPAddress mdnsMulticastIPAddr = IPAddress(224, 0, 0, 251);
#define MDNS_SERVER_PORT 5353 #define MDNS_SERVER_PORT 5353
// dotToLen()
// converts stings of form ".foo.barbar.x" to a string with the
// dots replaced with lenght. So string above would result in
// "\x03foo\x06barbar\x01x" in C notation. If not NULL, *substr
// will point to the beginning of the last component, in this
// example that would be "\x01x".
//
static void dotToLen(char *str, char **substr) {
char *dotplace = NULL;
char *s;
byte charcount = 0;
for (s = str;/*see break*/ ; s++) {
if (*s == '.' || *s == '\0') {
// take care of accumulated
if (dotplace != NULL && charcount != 0) {
*dotplace = charcount;
}
if (*s == '\0')
break;
if (substr && *s == '.')
*substr = s;
// set new values
dotplace = s;
charcount = 0;
} else {
charcount++;
}
}
}
MDNS::MDNS(EthernetUDP& udp) { MDNS::MDNS(EthernetUDP& udp) {
_udp = &udp; _udp = &udp;
} }
MDNS::~MDNS() { MDNS::~MDNS() {
_udp->stop(); _udp->stop();
if (_name) free(_name);
if (_serviceName) free(_serviceName);
if (_serviceProto) free(_serviceProto);
} }
int MDNS::begin(const IPAddress& ip, char* name) { int MDNS::begin(const IPAddress& ip, char* name) {
// if we were called very soon after the board was booted, we need to give the // if we were called very soon after the board was booted, we need to give the
@ -21,56 +55,53 @@ int MDNS::begin(const IPAddress& ip, char* name) {
// delay(100); // delay(100);
_ipAddress = ip; _ipAddress = ip;
_name = name; _name = (char *)malloc(strlen(name +2));
byte n;
for(n = 0; n<strlen(name); n++)
_name[n+1] = name[n];
_name[n+1] = '\0';
_name[0] = '.';
dotToLen(_name, NULL);
return _udp->beginMulticast(mdnsMulticastIPAddr, MDNS_SERVER_PORT); return _udp->beginMulticast(mdnsMulticastIPAddr, MDNS_SERVER_PORT);
} }
int MDNS::addServiceRecord(const char* name, uint16_t port, MDNSServiceProtocol_t proto) { int MDNS::addServiceRecord(const char* name, uint16_t port, MDNSServiceProtocol_t proto) {
// we ignore proto, assume TCP // we ignore proto, assume TCP
_serviceName = (char *)malloc(strlen(name +2)); _serviceName = (char *)malloc(strlen(name +2));
DIAG("name %d %s", strlen(name), name);
byte n; byte n;
for(n = 0; n<strlen(name); n++) for(n = 0; n<strlen(name); n++)
_serviceName[n+1] = name[n]; _serviceName[n+1] = name[n];
_serviceName[n+1] = '\0'; _serviceName[n+1] = '\0';
//strcpy(&_serviceName[1], name); _serviceName[0] = '.';
_serviceName[0] = (byte)strlen(name); _serviceProto = NULL; //to be filled in
DIAG("sn %d", *_serviceName); dotToLen(_serviceName, &_serviceProto);
_servicePort = port; _servicePort = port;
DIAG("Sevicename %d %s", strlen(_serviceName), _serviceName);
return 1; return 1;
} }
static char dns_rr_services[] = "\x09_services\x07_dns-sd\x04_udp\x05local"; static char dns_rr_services[] = "\x09_services\x07_dns-sd\x04_udp\x05local";
static char dns_rr_withrottle[] = "\x0b_withrottle\x04_tcp\x05local"; static char *dns_rr_tcplocal = "\x04_tcp\x05local";
static char *dns_rr_tcplocal = dns_rr_withrottle + dns_rr_withrottle[0] + 1; // jump over first record
static char *dns_rr_local = dns_rr_tcplocal + dns_rr_tcplocal[0] + 1; static char *dns_rr_local = dns_rr_tcplocal + dns_rr_tcplocal[0] + 1;
typedef struct _DNSHeader_t typedef struct _DNSHeader_t
{ {
uint16_t xid; uint16_t xid;
uint16_t flags; uint16_t flags; // flags condensed
/*
uint8_t recursionDesired : 1;
uint8_t truncated : 1;
uint8_t authoritiveAnswer : 1;
uint8_t opCode : 4;
uint8_t queryResponse : 1;
uint8_t responseCode : 4;
uint8_t checkingDisabled : 1;
uint8_t authenticatedData : 1;
uint8_t zReserved : 1;
uint8_t recursionAvailable : 1;
*/
uint16_t queryCount; uint16_t queryCount;
uint16_t answerCount; uint16_t answerCount;
uint16_t authorityCount; uint16_t authorityCount;
uint16_t additionalCount; uint16_t additionalCount;
} __attribute__((__packed__)) DNSHeader_t; } __attribute__((__packed__)) DNSHeader_t;
//
// MDNS::run()
// This broadcasts whatever we got evey BROADCASTTIME seconds.
// Why? Too much brokenness i all mDNS implementations available
//
void MDNS::run() { void MDNS::run() {
static long int lastrun = 10000; static long int lastrun = BROADCASTTIME * 1000UL;
unsigned long int now = millis(); unsigned long int now = millis();
if (!(now - lastrun > 10000)) { if (!(now - lastrun > BROADCASTTIME * 1000UL)) {
return; return;
} }
lastrun = now; lastrun = now;
@ -80,33 +111,39 @@ void MDNS::run() {
// dns header // dns header
dnsHeader.flags = lwip_htons(0x8400); // Response, authorative dnsHeader.flags = lwip_htons(0x8400); // Response, authorative
dnsHeader.answerCount = lwip_htons(4 /*5*/); dnsHeader.answerCount = lwip_htons(4 /*5 if TXT but we do not do that */);
_udp->write((uint8_t*)&dnsHeader, sizeof(DNSHeader_t)); _udp->write((uint8_t*)&dnsHeader, sizeof(DNSHeader_t));
// rr #1
// rr #1, the PTR record from generic _services.x.local to service.x.local
_udp->write((uint8_t*)dns_rr_services, sizeof(dns_rr_services)); _udp->write((uint8_t*)dns_rr_services, sizeof(dns_rr_services));
byte buf[10]; byte buf[10];
buf[0] = 0x00; buf[0] = 0x00;
buf[1] = 0x0c; //PTR buf[1] = 0x0c; //PTR
buf[2] = 0x00; buf[2] = 0x00;
buf[3] = 0x01; //IN buf[3] = 0x01; //IN
*((uint32_t*)(buf+4)) = lwip_htonl(120); //TTL in sec *((uint32_t*)(buf+4)) = lwip_htonl(120); //TTL in sec
*((uint16_t*)(buf+8)) = lwip_htons(sizeof(dns_rr_withrottle)); *((uint16_t*)(buf+8)) = lwip_htons( _serviceProto[0] + 1 + strlen(dns_rr_tcplocal) + 1);
_udp->write(buf, 10);
_udp->write(dns_rr_withrottle, sizeof(dns_rr_withrottle));
// rr #2
_udp->write(dns_rr_withrottle, sizeof(dns_rr_withrottle));
*((uint16_t*)(buf+8)) = lwip_htons(strlen(_serviceName) + sizeof(dns_rr_withrottle)); // recycle most of buf
_udp->write(buf, 10); _udp->write(buf, 10);
_udp->write(_serviceName, _serviceName[0]+1); _udp->write(_serviceProto,_serviceProto[0]+1);
_udp->write(dns_rr_withrottle, sizeof(dns_rr_withrottle)); _udp->write(dns_rr_tcplocal, strlen(dns_rr_tcplocal)+1);
// rr #3
_udp->write(_serviceName, _serviceName[0]+1); // rr #2, the PTR record from proto.x to name.proto.x
_udp->write(dns_rr_withrottle, sizeof(dns_rr_withrottle)); _udp->write(_serviceProto,_serviceProto[0]+1);
_udp->write(dns_rr_tcplocal, strlen(dns_rr_tcplocal)+1);
*((uint16_t*)(buf+8)) = lwip_htons(strlen(_serviceName) + strlen(dns_rr_tcplocal) + 1); // recycle most of buf
_udp->write(buf, 10);
_udp->write(_serviceName, strlen(_serviceName));
_udp->write(dns_rr_tcplocal, strlen(dns_rr_tcplocal)+1);
// rr #3, the SRV record for the service that points to local name
_udp->write(_serviceName, strlen(_serviceName));
_udp->write(dns_rr_tcplocal, strlen(dns_rr_tcplocal)+1);
buf[1] = 0x21; // recycle most of buf but here SRV buf[1] = 0x21; // recycle most of buf but here SRV
buf[2] = 0x80; // cache flush buf[2] = 0x80; // cache flush
*((uint16_t*)(buf+8)) = lwip_htons(strlen(_serviceName) + strlen(dns_rr_local) + 1 + 6); *((uint16_t*)(buf+8)) = lwip_htons(strlen(_name) + strlen(dns_rr_local) + 1 + 6);
_udp->write(buf, 10); _udp->write(buf, 10);
byte srv[6]; byte srv[6];
@ -116,11 +153,11 @@ void MDNS::run() {
*((uint16_t*)(srv+4)) = lwip_htons(_servicePort); *((uint16_t*)(srv+4)) = lwip_htons(_servicePort);
_udp->write(srv, 6); _udp->write(srv, 6);
// target // target
_udp->write(_serviceName, _serviceName[0]+1); _udp->write(_name, _name[0]+1);
_udp->write(dns_rr_local, strlen(dns_rr_local)+1); _udp->write(dns_rr_local, strlen(dns_rr_local)+1);
// rr #4 // rr #4, the A record for the name.local
_udp->write(_serviceName, _serviceName[0]+1); _udp->write(_name, _name[0]+1);
_udp->write(dns_rr_local, strlen(dns_rr_local)+1); _udp->write(dns_rr_local, strlen(dns_rr_local)+1);
buf[1] = 0x01; // recycle most of buf but here A buf[1] = 0x01; // recycle most of buf but here A

View File

@ -1,3 +1,6 @@
#define BROADCASTTIME 15 //seconds
typedef enum _MDNSServiceProtocol_t typedef enum _MDNSServiceProtocol_t
{ {
MDNSServiceTCP, MDNSServiceTCP,
@ -16,5 +19,6 @@ private:
IPAddress _ipAddress; IPAddress _ipAddress;
char* _name; char* _name;
char* _serviceName; char* _serviceName;
char* _serviceProto;
int _servicePort; int _servicePort;
}; };

View File

@ -132,9 +132,8 @@ void EthernetInterface::setup()
#ifdef DO_MDNS #ifdef DO_MDNS
if (!mdns.begin(Ethernet.localIP(), WIFI_HOSTNAME)) if (!mdns.begin(Ethernet.localIP(), WIFI_HOSTNAME))
DIAG("mdns.begin fail"); // hostname DIAG("mdns.begin fail"); // hostname
mdns.addServiceRecord(WIFI_HOSTNAME, IP_PORT, MDNSServiceTCP); mdns.addServiceRecord(WIFI_HOSTNAME "._withrottle", IP_PORT, MDNSServiceTCP);
// Not sure if we need to run it once, but just in case! mdns.run(); // run it right away to get out info ASAP
mdns.run();
#endif #endif
connected=true; connected=true;
} }