From 4668b3ac606a7cab3554e7e6a4af1342f008a43b Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 13 Jul 2016 16:11:52 +0300 Subject: [PATCH 1/2] Implement Async NBNS (NetBIOS) Name resolution for windows Source: http://www.xpablo.cz/?p=751#more-751 --- libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp | 272 ++++++++++++++++++ libraries/ESP8266NetBIOS/ESP8266NetBIOS.h | 38 +++ .../examples/ESPNBNST/espnbnst.ino | 49 ++++ libraries/ESP8266NetBIOS/keywords.txt | 24 ++ libraries/ESP8266NetBIOS/library.properties | 9 + 5 files changed, 392 insertions(+) create mode 100755 libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp create mode 100755 libraries/ESP8266NetBIOS/ESP8266NetBIOS.h create mode 100755 libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino create mode 100755 libraries/ESP8266NetBIOS/keywords.txt create mode 100644 libraries/ESP8266NetBIOS/library.properties diff --git a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp new file mode 100755 index 0000000000..f84f4a48ea --- /dev/null +++ b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp @@ -0,0 +1,272 @@ +/* Klient sluzby NBNS + */ + +#include "ESP8266NetBIOS.h" + +#include + +extern "C" { + #include "osapi.h" + #include "ets_sys.h" + #include "user_interface.h" +} + +#include "WiFiUdp.h" +#include "lwip/opt.h" +#include "lwip/inet.h" +#include "lwip/udp.h" + +#define NBNSQ_TYPE_NB (0x0020) +#define NBNSQ_CLASS_IN (0x0001) + +// Definice struktury NBNS dotazu (alespon veci, ktere jsem vypozoroval): +struct NBNSQUESTION +{ + uint16_t NBNSQ_ID; // ID dotazu + uint8_t NBNSQ_FLAGS1; + uint8_t NBNSQ_FLAGS2; + uint16_t NBNSQ_QUESTIONCOUNT; + uint16_t NBNSQ_ANSWERCOUNT; + uint16_t NBNSQ_AUTHORITYCOUNT; + uint16_t NBNSQ_ADDITIONALRECORDCOUNT; + uint8_t NBNSQ_NAMESIZE; // delka nasledujiciho retezce + char NBNSQ_NAME[32+1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha + uint16_t NBNSQ_TYPE; + uint16_t NBNSQ_CLASS; +} __attribute__((packed)); + +// Definice struktury NBNS odpovedi (stejne jako u dotazu) +struct NBNSANSWER +{ + uint16_t NBNSA_ID; // ID dotazu + uint8_t NBNSA_FLAGS1; + uint8_t NBNSA_FLAGS2; + uint16_t NBNSA_QUESTIONCOUNT; + uint16_t NBNSA_ANSWERCOUNT; + uint16_t NBNSA_AUTHORITYCOUNT; + uint16_t NBNSA_ADDITIONALRECORDCOUNT; + uint8_t NBNSA_NAMESIZE; // delka nasledujiciho retezce + char NBNSA_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha + uint16_t NBNSA_TYPE; + uint16_t NBNSA_CLASS; + uint32_t NBNSA_TIMETOLIVE; + uint16_t NBNSA_LENGTH; + uint16_t NBNSA_NODEFLAGS; // POZOR!!! tady si nejsem moc jisty + uint32_t NBNSA_NODEADDRESS; +} __attribute__((packed)); + +// Definice struktury NBNS odpovedi na dotaz na jmeno +struct NBNSANSWERN +{ + uint16_t NBNSAN_ID; // ID dotazu + uint8_t NBNSAN_FLAGS1; + uint8_t NBNSAN_FLAGS2; + uint16_t NBNSAN_QUESTIONCOUNT; + uint16_t NBNSAN_ANSWERCOUNT; + uint16_t NBNSAN_AUTHORITYCOUNT; + uint16_t NBNSAN_ADDITIONALRECORDCOUNT; + uint8_t NBNSAN_NAMESIZE; // delka nasledujiciho retezce + char NBNSAN_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha + uint16_t NBNSAN_TYPE; + uint16_t NBNSAN_CLASS; + uint32_t NBNSAN_TIMETOLIVE; + uint16_t NBNSAN_LENGTH; + uint8_t NBNSAN_NUMBER; // number of names + char NBNSAN_NNAME[15]; // jmeno nodu + uint8_t NBNSAN_NTYPE; // typ jmena + uint16_t NBNSAN_NFLAGS; // node flags +} __attribute__((packed)); + +static WiFiUDP _udp; // A UDP instance to let us send and receive packets over UDP + +/** Metoda pro ziskani jmena z kodovani NETBIOS. + * \param nbname Ukazatel na jmeno v NETBIOS kodovani. + * \param name Ukazatel na misto, kam prevadime jmeno. + * \param maxlen Maximalni pocet znaku v nbname. + */ +void ESP8266NetBIOS::_getnbname(char *nbname, char *name, uint8_t maxlen) +{ + uint8_t b; + uint8_t c = 0; + + while ((*nbname != 0x0) && (c < maxlen)) + { + b = (*nbname++ - 'A') << 4; // opravime nibble a prevedeme ho do vyssich bitu + c++; // pocitame pocet odebranych bytu + if (*nbname != 0x0) + { + b |= *nbname++ - 'A'; // pridame nizsi nibble + c++; // opet spocitame pocet odebranych znaku + } + *name++ = b; // ulozime znak do vysledku a posuneme ukazatel + } + *name = 0x0; // ulozime ukoncovaci 0 +} + +/** Prevod zadaneho textu do NETBIOS kodovani + * \param name Ukazatel na prevadene jmeno. + * \param nbname Ukazatel na misto, kam vytvarime jmeno. + * \param outlen Pocet vystupnich znaku (mimo ukoncovaci 0) musi byt delitelne 2 + */ +void ESP8266NetBIOS::_makenbname(char *name, char *nbname, uint8_t outlen) +{ + uint8_t b; + uint8_t c = 0; + + while (c < (outlen - 2)) + { + b = *name; // prevadeny znak + if (b) + name++; // zatim se posunujeme + else + b = 0x20; // konec retezce je nahrazeny mezerou + *nbname++ = (b >> 4) + 'A'; // jeden nibble ze znaku + *nbname++ = (b & 0xf) + 'A'; // druhy nibble ze znaku + c += 2; // pocet prevedenych znaku + } + *nbname++ = 'A'; + *nbname++ = 'A'; // ulozime ukoncovaci 0 v NBNS kodovani + *nbname = 0; // ulozime ukoncovaci 0 retezce +} + +ESP8266NetBIOS::ESP8266NetBIOS():_pcb(NULL) +{ + +} +ESP8266NetBIOS::~ESP8266NetBIOS() +{ + end(); +} + +// Vytvoreni a otevreni UDP soketu, pokud jeste neni... +bool ESP8266NetBIOS::begin(const char *name) +{ + size_t n = strlen(name); + if (n > sizeof(_name)) + { // prilis dlouhe jmeno + return false; + } + + // presuneme jmeno zarizeni se soucasnou upravou na UPPER case + for (int i = 0; i < n; ++i) + _name[i] = toupper(name[i]); + _name[n] = '\0'; + + if(_pcb != NULL){ + return true; + } + ip_addr_t addr; + addr.addr = INADDR_ANY; + _pcb = udp_new(); + udp_recv(_pcb, &_s_recv, (void *) this); + err_t err = udp_bind(_pcb, &addr, NBNS_PORT); + if(err != ERR_OK){ + end(); + return false; + } + return true; +} + +void ESP8266NetBIOS::end(){ + if(_pcb != NULL){ + udp_remove(_pcb); + _pcb = NULL; + } +} + +void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, ip_addr_t *addr, u16_t port) +{ + while(pb != NULL){ + uint8_t * data = (uint8_t*)((pb)->payload); + size_t len = pb->len; + ip_hdr* iphdr = reinterpret_cast(data - UDP_HLEN - IP_HLEN); + ip_addr_t saddr; + saddr.addr = iphdr->src.addr; + + if (len >= sizeof(struct NBNSQUESTION)) + { + struct NBNSQUESTION * question = (struct NBNSQUESTION *)data; + if (0 == (question->NBNSQ_FLAGS1 & 0x80)) + { + char name[ NBNS_MAX_HOSTNAME_LEN + 1 ]; // dekodovane dotazovane jmeno + char *str; // pomocna promenna, pouze pro praci s retezcem + + _getnbname(&question->NBNSQ_NAME[0], (char *)&name, question->NBNSQ_NAMESIZE); // prevedeme dotazovane jmeno + if ((str = strchr(name, ' ')) != NULL)// jmeno hledaneho zarizeni v tomto pripade ukoncuje i mezera + *str = '\0'; // ukoncime retezec na vyskytu prvni mezery + + if (0 == strcmp(name, _name)) + { // dotaz primo na nas + struct NBNSANSWER nbnsa; // buffer, do ktereho je sestavena odpoved na dotaz + + nbnsa.NBNSA_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi + nbnsa.NBNSA_FLAGS1 = 0x85; // priznak odpovedi + nbnsa.NBNSA_FLAGS2 = 0; // vlajky 2 a response code + nbnsa.NBNSA_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi + nbnsa.NBNSA_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_NAMESIZE = sizeof(nbnsa.NBNSA_NAME) - 1; // prekopirujeme delku jmena stanice + _makenbname(_name, &nbnsa.NBNSA_NAME[0], sizeof(nbnsa.NBNSA_NAME) - 1); // prevedeme jmeno + nbnsa.NBNSA_TYPE = LWIP_PLATFORM_HTONS(0x20); // NetBIOS name + nbnsa.NBNSA_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name + nbnsa.NBNSA_TIMETOLIVE = LWIP_PLATFORM_HTONL(300000UL);// Time to live (30000 sekund) + nbnsa.NBNSA_LENGTH = LWIP_PLATFORM_HTONS(6); + nbnsa.NBNSA_NODEFLAGS = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_NODEADDRESS = WiFi.localIP(); // ulozime nasi IP adresu + + pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsa), PBUF_RAM); + if(pbt != NULL){ + uint8_t* dst = reinterpret_cast(pbt->payload); + memcpy(dst, (uint8_t *)&nbnsa, sizeof(nbnsa)); + udp_sendto(_pcb, pbt, &saddr, NBNS_PORT); + pbuf_free(pbt); + } + } + else if (0 == strcmp(name, "*")) + { // obecny dotaz - mireny nejspis na nasi IP adresu + struct NBNSANSWERN nbnsan; // buffer, do ktereho je sestavena odpoved na dotaz + + nbnsan.NBNSAN_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi + nbnsan.NBNSAN_FLAGS1 = 0x84; // priznak odpovedi + nbnsan.NBNSAN_FLAGS2 = 0; // vlajky 2 a response code + nbnsan.NBNSAN_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsan.NBNSAN_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi + nbnsan.NBNSAN_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsan.NBNSAN_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsan.NBNSAN_NAMESIZE = question->NBNSQ_NAMESIZE; // prekopirujeme delku jmena stanice + memcpy(nbnsan.NBNSAN_NAME, question->NBNSQ_NAME, sizeof(nbnsan.NBNSAN_NAME)); // prekopirujeme dotazovane jmeno + nbnsan.NBNSAN_TYPE = LWIP_PLATFORM_HTONS(0x21); // NBSTAT + nbnsan.NBNSAN_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name + nbnsan.NBNSAN_TIMETOLIVE = LWIP_PLATFORM_HTONL(0); + nbnsan.NBNSAN_LENGTH = LWIP_PLATFORM_HTONS(4 + sizeof(nbnsan.NBNSAN_NNAME)); + nbnsan.NBNSAN_NUMBER = 1; // Number of names + memset(nbnsan.NBNSAN_NNAME, 0x20, sizeof(nbnsan.NBNSAN_NNAME)); + memcpy(nbnsan.NBNSAN_NNAME, _name, strlen(_name)); + nbnsan.NBNSAN_NTYPE = 0; // Workstation/Redirector + nbnsan.NBNSAN_NFLAGS = LWIP_PLATFORM_HTONS(0x400); // b-node, unique, active + + pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsan), PBUF_RAM); + if(pbt != NULL){ + uint8_t* dst = reinterpret_cast(pbt->payload); + memcpy(dst, (uint8_t *)&nbnsan, sizeof(nbnsan)); + udp_sendto(_pcb, pbt, &saddr, NBNS_PORT); + pbuf_free(pbt); + } + } + } + } + + pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + pbuf_free(this_pb); + } +} + +void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, struct ip_addr *addr, uint16_t port){ + reinterpret_cast(arg)->_recv(upcb, p, addr, port); +} + +ESP8266NetBIOS NBNS; +// EOF diff --git a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h new file mode 100755 index 0000000000..47c048ae29 --- /dev/null +++ b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h @@ -0,0 +1,38 @@ +// +#ifndef __ESPNBNS_h__ +#define __ESPNBNS_h__ + +#include + +#define NBNS_PORT 137 +/** +* @def NBNS_MAX_HOSTNAME_LEN +* @brief maximalni delka NBNS jmena zarizeni +* @remarks +* Jmeno zarizeni musi byt uvedeno VELKYMI pismenami a nesmi obsahovat mezery (whitespaces). +*/ +#define NBNS_MAX_HOSTNAME_LEN 16 + +struct udp_pcb; +struct pbuf; +struct ip_addr; + +class ESP8266NetBIOS +{ + protected: + udp_pcb* _pcb; + char _name[NBNS_MAX_HOSTNAME_LEN + 1]; + void _getnbname(char *nbname, char *name, uint8_t maxlen); + void _makenbname(char *name, char *nbname, uint8_t outlen); + void _recv(udp_pcb *upcb, pbuf *pb, struct ip_addr *addr, uint16_t port); + static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, struct ip_addr *addr, uint16_t port); + public: + ESP8266NetBIOS(); + ~ESP8266NetBIOS(); + bool begin(const char *name); + void end(); +}; + +extern ESP8266NetBIOS NBNS; + +#endif diff --git a/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino b/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino new file mode 100755 index 0000000000..c3afe2fa7b --- /dev/null +++ b/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino @@ -0,0 +1,49 @@ +#include +#include +#include + +const char* ssid = "............"; +const char* password = ".............."; + +ESP8266WebServer wwwserver(80); +String content; + +static void handleRoot(void) +{ + content = F("\nHello world from ESP8266"); + content += F("

"); + content += F(""); + + wwwserver.send(200, F("text/html"), content); +} + +void setup() +{ + Serial.begin(115200); + + // Connect to WiFi network + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + + wwwserver.on("/", handleRoot); + wwwserver.begin(); + + NBNS.begin("ESP"); +} + +void loop() +{ + wwwserver.handleClient(); +} diff --git a/libraries/ESP8266NetBIOS/keywords.txt b/libraries/ESP8266NetBIOS/keywords.txt new file mode 100755 index 0000000000..41f45d5e25 --- /dev/null +++ b/libraries/ESP8266NetBIOS/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map For ESPNBNS +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +NBNS KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/ESP8266NetBIOS/library.properties b/libraries/ESP8266NetBIOS/library.properties new file mode 100644 index 0000000000..510f9937c9 --- /dev/null +++ b/libraries/ESP8266NetBIOS/library.properties @@ -0,0 +1,9 @@ +name=ESP8266NetBIOS +version=1.0 +author=Pablo@xpablo.cz +maintainer=Hristo Gochkov +sentence=Enables NBNS (NetBIOS) name resolution. +paragraph=With this library you can connect to your ESP from Windows using a short name +category=Communication +url=http://www.xpablo.cz/?p=751#more-751 +architectures=esp8266 From 96e2ccc264c4ad637ad5d6d6542c791ced178122 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Wed, 13 Jul 2016 18:45:29 +0300 Subject: [PATCH 2/2] Format code and remove missed old code --- libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp | 377 +++++++++--------- libraries/ESP8266NetBIOS/ESP8266NetBIOS.h | 4 +- .../examples/ESPNBNST/espnbnst.ino | 44 +- 3 files changed, 209 insertions(+), 216 deletions(-) diff --git a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp index f84f4a48ea..f38f4b58ca 100755 --- a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp +++ b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.cpp @@ -6,12 +6,11 @@ #include extern "C" { - #include "osapi.h" - #include "ets_sys.h" - #include "user_interface.h" +#include "osapi.h" +#include "ets_sys.h" +#include "user_interface.h" } -#include "WiFiUdp.h" #include "lwip/opt.h" #include "lwip/inet.h" #include "lwip/udp.h" @@ -20,65 +19,60 @@ extern "C" { #define NBNSQ_CLASS_IN (0x0001) // Definice struktury NBNS dotazu (alespon veci, ktere jsem vypozoroval): -struct NBNSQUESTION -{ - uint16_t NBNSQ_ID; // ID dotazu - uint8_t NBNSQ_FLAGS1; - uint8_t NBNSQ_FLAGS2; - uint16_t NBNSQ_QUESTIONCOUNT; - uint16_t NBNSQ_ANSWERCOUNT; - uint16_t NBNSQ_AUTHORITYCOUNT; - uint16_t NBNSQ_ADDITIONALRECORDCOUNT; - uint8_t NBNSQ_NAMESIZE; // delka nasledujiciho retezce - char NBNSQ_NAME[32+1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha - uint16_t NBNSQ_TYPE; - uint16_t NBNSQ_CLASS; +struct NBNSQUESTION { + uint16_t NBNSQ_ID; // ID dotazu + uint8_t NBNSQ_FLAGS1; + uint8_t NBNSQ_FLAGS2; + uint16_t NBNSQ_QUESTIONCOUNT; + uint16_t NBNSQ_ANSWERCOUNT; + uint16_t NBNSQ_AUTHORITYCOUNT; + uint16_t NBNSQ_ADDITIONALRECORDCOUNT; + uint8_t NBNSQ_NAMESIZE; // delka nasledujiciho retezce + char NBNSQ_NAME[32+1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha + uint16_t NBNSQ_TYPE; + uint16_t NBNSQ_CLASS; } __attribute__((packed)); // Definice struktury NBNS odpovedi (stejne jako u dotazu) -struct NBNSANSWER -{ - uint16_t NBNSA_ID; // ID dotazu - uint8_t NBNSA_FLAGS1; - uint8_t NBNSA_FLAGS2; - uint16_t NBNSA_QUESTIONCOUNT; - uint16_t NBNSA_ANSWERCOUNT; - uint16_t NBNSA_AUTHORITYCOUNT; - uint16_t NBNSA_ADDITIONALRECORDCOUNT; - uint8_t NBNSA_NAMESIZE; // delka nasledujiciho retezce - char NBNSA_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha - uint16_t NBNSA_TYPE; - uint16_t NBNSA_CLASS; - uint32_t NBNSA_TIMETOLIVE; - uint16_t NBNSA_LENGTH; - uint16_t NBNSA_NODEFLAGS; // POZOR!!! tady si nejsem moc jisty - uint32_t NBNSA_NODEADDRESS; +struct NBNSANSWER { + uint16_t NBNSA_ID; // ID dotazu + uint8_t NBNSA_FLAGS1; + uint8_t NBNSA_FLAGS2; + uint16_t NBNSA_QUESTIONCOUNT; + uint16_t NBNSA_ANSWERCOUNT; + uint16_t NBNSA_AUTHORITYCOUNT; + uint16_t NBNSA_ADDITIONALRECORDCOUNT; + uint8_t NBNSA_NAMESIZE; // delka nasledujiciho retezce + char NBNSA_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha + uint16_t NBNSA_TYPE; + uint16_t NBNSA_CLASS; + uint32_t NBNSA_TIMETOLIVE; + uint16_t NBNSA_LENGTH; + uint16_t NBNSA_NODEFLAGS; // POZOR!!! tady si nejsem moc jisty + uint32_t NBNSA_NODEADDRESS; } __attribute__((packed)); // Definice struktury NBNS odpovedi na dotaz na jmeno -struct NBNSANSWERN -{ - uint16_t NBNSAN_ID; // ID dotazu - uint8_t NBNSAN_FLAGS1; - uint8_t NBNSAN_FLAGS2; - uint16_t NBNSAN_QUESTIONCOUNT; - uint16_t NBNSAN_ANSWERCOUNT; - uint16_t NBNSAN_AUTHORITYCOUNT; - uint16_t NBNSAN_ADDITIONALRECORDCOUNT; - uint8_t NBNSAN_NAMESIZE; // delka nasledujiciho retezce - char NBNSAN_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha - uint16_t NBNSAN_TYPE; - uint16_t NBNSAN_CLASS; - uint32_t NBNSAN_TIMETOLIVE; - uint16_t NBNSAN_LENGTH; - uint8_t NBNSAN_NUMBER; // number of names - char NBNSAN_NNAME[15]; // jmeno nodu - uint8_t NBNSAN_NTYPE; // typ jmena - uint16_t NBNSAN_NFLAGS; // node flags +struct NBNSANSWERN { + uint16_t NBNSAN_ID; // ID dotazu + uint8_t NBNSAN_FLAGS1; + uint8_t NBNSAN_FLAGS2; + uint16_t NBNSAN_QUESTIONCOUNT; + uint16_t NBNSAN_ANSWERCOUNT; + uint16_t NBNSAN_AUTHORITYCOUNT; + uint16_t NBNSAN_ADDITIONALRECORDCOUNT; + uint8_t NBNSAN_NAMESIZE; // delka nasledujiciho retezce + char NBNSAN_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha + uint16_t NBNSAN_TYPE; + uint16_t NBNSAN_CLASS; + uint32_t NBNSAN_TIMETOLIVE; + uint16_t NBNSAN_LENGTH; + uint8_t NBNSAN_NUMBER; // number of names + char NBNSAN_NNAME[15]; // jmeno nodu + uint8_t NBNSAN_NTYPE; // typ jmena + uint16_t NBNSAN_NFLAGS; // node flags } __attribute__((packed)); -static WiFiUDP _udp; // A UDP instance to let us send and receive packets over UDP - /** Metoda pro ziskani jmena z kodovani NETBIOS. * \param nbname Ukazatel na jmeno v NETBIOS kodovani. * \param name Ukazatel na misto, kam prevadime jmeno. @@ -86,21 +80,19 @@ static WiFiUDP _udp; // A UDP instance to let us send and receive packets over */ void ESP8266NetBIOS::_getnbname(char *nbname, char *name, uint8_t maxlen) { - uint8_t b; - uint8_t c = 0; + uint8_t b; + uint8_t c = 0; - while ((*nbname != 0x0) && (c < maxlen)) - { - b = (*nbname++ - 'A') << 4; // opravime nibble a prevedeme ho do vyssich bitu - c++; // pocitame pocet odebranych bytu - if (*nbname != 0x0) - { - b |= *nbname++ - 'A'; // pridame nizsi nibble - c++; // opet spocitame pocet odebranych znaku - } - *name++ = b; // ulozime znak do vysledku a posuneme ukazatel - } - *name = 0x0; // ulozime ukoncovaci 0 + while ((*nbname != 0x0) && (c < maxlen)) { + b = (*nbname++ - 'A') << 4; // opravime nibble a prevedeme ho do vyssich bitu + c++; // pocitame pocet odebranych bytu + if (*nbname != 0x0) { + b |= *nbname++ - 'A'; // pridame nizsi nibble + c++; // opet spocitame pocet odebranych znaku + } + *name++ = b; // ulozime znak do vysledku a posuneme ukazatel + } + *name = 0x0; // ulozime ukoncovaci 0 } /** Prevod zadaneho textu do NETBIOS kodovani @@ -110,23 +102,23 @@ void ESP8266NetBIOS::_getnbname(char *nbname, char *name, uint8_t maxlen) */ void ESP8266NetBIOS::_makenbname(char *name, char *nbname, uint8_t outlen) { - uint8_t b; - uint8_t c = 0; + uint8_t b; + uint8_t c = 0; - while (c < (outlen - 2)) - { - b = *name; // prevadeny znak - if (b) - name++; // zatim se posunujeme - else - b = 0x20; // konec retezce je nahrazeny mezerou - *nbname++ = (b >> 4) + 'A'; // jeden nibble ze znaku - *nbname++ = (b & 0xf) + 'A'; // druhy nibble ze znaku - c += 2; // pocet prevedenych znaku - } - *nbname++ = 'A'; - *nbname++ = 'A'; // ulozime ukoncovaci 0 v NBNS kodovani - *nbname = 0; // ulozime ukoncovaci 0 retezce + while (c < (outlen - 2)) { + b = *name; // prevadeny znak + if (b) { + name++; // zatim se posunujeme + } else { + b = 0x20; // konec retezce je nahrazeny mezerou + } + *nbname++ = (b >> 4) + 'A'; // jeden nibble ze znaku + *nbname++ = (b & 0xf) + 'A'; // druhy nibble ze znaku + c += 2; // pocet prevedenych znaku + } + *nbname++ = 'A'; + *nbname++ = 'A'; // ulozime ukoncovaci 0 v NBNS kodovani + *nbname = 0; // ulozime ukoncovaci 0 retezce } ESP8266NetBIOS::ESP8266NetBIOS():_pcb(NULL) @@ -135,137 +127,138 @@ ESP8266NetBIOS::ESP8266NetBIOS():_pcb(NULL) } ESP8266NetBIOS::~ESP8266NetBIOS() { - end(); + end(); } // Vytvoreni a otevreni UDP soketu, pokud jeste neni... bool ESP8266NetBIOS::begin(const char *name) { - size_t n = strlen(name); - if (n > sizeof(_name)) - { // prilis dlouhe jmeno - return false; - } + size_t n = strlen(name); + if (n > sizeof(_name)) { + // prilis dlouhe jmeno + return false; + } - // presuneme jmeno zarizeni se soucasnou upravou na UPPER case - for (int i = 0; i < n; ++i) - _name[i] = toupper(name[i]); - _name[n] = '\0'; + // presuneme jmeno zarizeni se soucasnou upravou na UPPER case + for (int i = 0; i < n; ++i) { + _name[i] = toupper(name[i]); + } + _name[n] = '\0'; - if(_pcb != NULL){ + if(_pcb != NULL) { + return true; + } + ip_addr_t addr; + addr.addr = INADDR_ANY; + _pcb = udp_new(); + udp_recv(_pcb, &_s_recv, (void *) this); + err_t err = udp_bind(_pcb, &addr, NBNS_PORT); + if(err != ERR_OK) { + end(); + return false; + } return true; - } - ip_addr_t addr; - addr.addr = INADDR_ANY; - _pcb = udp_new(); - udp_recv(_pcb, &_s_recv, (void *) this); - err_t err = udp_bind(_pcb, &addr, NBNS_PORT); - if(err != ERR_OK){ - end(); - return false; - } - return true; } -void ESP8266NetBIOS::end(){ - if(_pcb != NULL){ - udp_remove(_pcb); - _pcb = NULL; - } +void ESP8266NetBIOS::end() +{ + if(_pcb != NULL) { + udp_remove(_pcb); + _pcb = NULL; + } } void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, ip_addr_t *addr, u16_t port) { - while(pb != NULL){ - uint8_t * data = (uint8_t*)((pb)->payload); - size_t len = pb->len; - ip_hdr* iphdr = reinterpret_cast(data - UDP_HLEN - IP_HLEN); - ip_addr_t saddr; - saddr.addr = iphdr->src.addr; + while(pb != NULL) { + uint8_t * data = (uint8_t*)((pb)->payload); + size_t len = pb->len; + ip_hdr* iphdr = reinterpret_cast(data - UDP_HLEN - IP_HLEN); + ip_addr_t saddr; + saddr.addr = iphdr->src.addr; - if (len >= sizeof(struct NBNSQUESTION)) - { - struct NBNSQUESTION * question = (struct NBNSQUESTION *)data; - if (0 == (question->NBNSQ_FLAGS1 & 0x80)) - { - char name[ NBNS_MAX_HOSTNAME_LEN + 1 ]; // dekodovane dotazovane jmeno - char *str; // pomocna promenna, pouze pro praci s retezcem + if (len >= sizeof(struct NBNSQUESTION)) { + struct NBNSQUESTION * question = (struct NBNSQUESTION *)data; + if (0 == (question->NBNSQ_FLAGS1 & 0x80)) { + char name[ NBNS_MAX_HOSTNAME_LEN + 1 ]; // dekodovane dotazovane jmeno + char *str; // pomocna promenna, pouze pro praci s retezcem - _getnbname(&question->NBNSQ_NAME[0], (char *)&name, question->NBNSQ_NAMESIZE); // prevedeme dotazovane jmeno - if ((str = strchr(name, ' ')) != NULL)// jmeno hledaneho zarizeni v tomto pripade ukoncuje i mezera - *str = '\0'; // ukoncime retezec na vyskytu prvni mezery + _getnbname(&question->NBNSQ_NAME[0], (char *)&name, question->NBNSQ_NAMESIZE); // prevedeme dotazovane jmeno + if ((str = strchr(name, ' ')) != NULL) { // jmeno hledaneho zarizeni v tomto pripade ukoncuje i mezera + *str = '\0'; // ukoncime retezec na vyskytu prvni mezery + } - if (0 == strcmp(name, _name)) - { // dotaz primo na nas - struct NBNSANSWER nbnsa; // buffer, do ktereho je sestavena odpoved na dotaz + if (0 == strcmp(name, _name)) { + // dotaz primo na nas + struct NBNSANSWER nbnsa; // buffer, do ktereho je sestavena odpoved na dotaz - nbnsa.NBNSA_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi - nbnsa.NBNSA_FLAGS1 = 0x85; // priznak odpovedi - nbnsa.NBNSA_FLAGS2 = 0; // vlajky 2 a response code - nbnsa.NBNSA_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0); - nbnsa.NBNSA_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi - nbnsa.NBNSA_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0); - nbnsa.NBNSA_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0); - nbnsa.NBNSA_NAMESIZE = sizeof(nbnsa.NBNSA_NAME) - 1; // prekopirujeme delku jmena stanice - _makenbname(_name, &nbnsa.NBNSA_NAME[0], sizeof(nbnsa.NBNSA_NAME) - 1); // prevedeme jmeno - nbnsa.NBNSA_TYPE = LWIP_PLATFORM_HTONS(0x20); // NetBIOS name - nbnsa.NBNSA_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name - nbnsa.NBNSA_TIMETOLIVE = LWIP_PLATFORM_HTONL(300000UL);// Time to live (30000 sekund) - nbnsa.NBNSA_LENGTH = LWIP_PLATFORM_HTONS(6); - nbnsa.NBNSA_NODEFLAGS = LWIP_PLATFORM_HTONS(0); - nbnsa.NBNSA_NODEADDRESS = WiFi.localIP(); // ulozime nasi IP adresu + nbnsa.NBNSA_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi + nbnsa.NBNSA_FLAGS1 = 0x85; // priznak odpovedi + nbnsa.NBNSA_FLAGS2 = 0; // vlajky 2 a response code + nbnsa.NBNSA_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi + nbnsa.NBNSA_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_NAMESIZE = sizeof(nbnsa.NBNSA_NAME) - 1; // prekopirujeme delku jmena stanice + _makenbname(_name, &nbnsa.NBNSA_NAME[0], sizeof(nbnsa.NBNSA_NAME) - 1); // prevedeme jmeno + nbnsa.NBNSA_TYPE = LWIP_PLATFORM_HTONS(0x20); // NetBIOS name + nbnsa.NBNSA_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name + nbnsa.NBNSA_TIMETOLIVE = LWIP_PLATFORM_HTONL(300000UL);// Time to live (30000 sekund) + nbnsa.NBNSA_LENGTH = LWIP_PLATFORM_HTONS(6); + nbnsa.NBNSA_NODEFLAGS = LWIP_PLATFORM_HTONS(0); + nbnsa.NBNSA_NODEADDRESS = WiFi.localIP(); // ulozime nasi IP adresu - pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsa), PBUF_RAM); - if(pbt != NULL){ - uint8_t* dst = reinterpret_cast(pbt->payload); - memcpy(dst, (uint8_t *)&nbnsa, sizeof(nbnsa)); - udp_sendto(_pcb, pbt, &saddr, NBNS_PORT); - pbuf_free(pbt); - } - } - else if (0 == strcmp(name, "*")) - { // obecny dotaz - mireny nejspis na nasi IP adresu - struct NBNSANSWERN nbnsan; // buffer, do ktereho je sestavena odpoved na dotaz + pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsa), PBUF_RAM); + if(pbt != NULL) { + uint8_t* dst = reinterpret_cast(pbt->payload); + memcpy(dst, (uint8_t *)&nbnsa, sizeof(nbnsa)); + udp_sendto(_pcb, pbt, &saddr, NBNS_PORT); + pbuf_free(pbt); + } + } else if (0 == strcmp(name, "*")) { + // obecny dotaz - mireny nejspis na nasi IP adresu + struct NBNSANSWERN nbnsan; // buffer, do ktereho je sestavena odpoved na dotaz - nbnsan.NBNSAN_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi - nbnsan.NBNSAN_FLAGS1 = 0x84; // priznak odpovedi - nbnsan.NBNSAN_FLAGS2 = 0; // vlajky 2 a response code - nbnsan.NBNSAN_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0); - nbnsan.NBNSAN_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi - nbnsan.NBNSAN_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0); - nbnsan.NBNSAN_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0); - nbnsan.NBNSAN_NAMESIZE = question->NBNSQ_NAMESIZE; // prekopirujeme delku jmena stanice - memcpy(nbnsan.NBNSAN_NAME, question->NBNSQ_NAME, sizeof(nbnsan.NBNSAN_NAME)); // prekopirujeme dotazovane jmeno - nbnsan.NBNSAN_TYPE = LWIP_PLATFORM_HTONS(0x21); // NBSTAT - nbnsan.NBNSAN_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name - nbnsan.NBNSAN_TIMETOLIVE = LWIP_PLATFORM_HTONL(0); - nbnsan.NBNSAN_LENGTH = LWIP_PLATFORM_HTONS(4 + sizeof(nbnsan.NBNSAN_NNAME)); - nbnsan.NBNSAN_NUMBER = 1; // Number of names - memset(nbnsan.NBNSAN_NNAME, 0x20, sizeof(nbnsan.NBNSAN_NNAME)); - memcpy(nbnsan.NBNSAN_NNAME, _name, strlen(_name)); - nbnsan.NBNSAN_NTYPE = 0; // Workstation/Redirector - nbnsan.NBNSAN_NFLAGS = LWIP_PLATFORM_HTONS(0x400); // b-node, unique, active + nbnsan.NBNSAN_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi + nbnsan.NBNSAN_FLAGS1 = 0x84; // priznak odpovedi + nbnsan.NBNSAN_FLAGS2 = 0; // vlajky 2 a response code + nbnsan.NBNSAN_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsan.NBNSAN_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi + nbnsan.NBNSAN_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsan.NBNSAN_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0); + nbnsan.NBNSAN_NAMESIZE = question->NBNSQ_NAMESIZE; // prekopirujeme delku jmena stanice + memcpy(nbnsan.NBNSAN_NAME, question->NBNSQ_NAME, sizeof(nbnsan.NBNSAN_NAME)); // prekopirujeme dotazovane jmeno + nbnsan.NBNSAN_TYPE = LWIP_PLATFORM_HTONS(0x21); // NBSTAT + nbnsan.NBNSAN_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name + nbnsan.NBNSAN_TIMETOLIVE = LWIP_PLATFORM_HTONL(0); + nbnsan.NBNSAN_LENGTH = LWIP_PLATFORM_HTONS(4 + sizeof(nbnsan.NBNSAN_NNAME)); + nbnsan.NBNSAN_NUMBER = 1; // Number of names + memset(nbnsan.NBNSAN_NNAME, 0x20, sizeof(nbnsan.NBNSAN_NNAME)); + memcpy(nbnsan.NBNSAN_NNAME, _name, strlen(_name)); + nbnsan.NBNSAN_NTYPE = 0; // Workstation/Redirector + nbnsan.NBNSAN_NFLAGS = LWIP_PLATFORM_HTONS(0x400); // b-node, unique, active - pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsan), PBUF_RAM); - if(pbt != NULL){ - uint8_t* dst = reinterpret_cast(pbt->payload); - memcpy(dst, (uint8_t *)&nbnsan, sizeof(nbnsan)); - udp_sendto(_pcb, pbt, &saddr, NBNS_PORT); - pbuf_free(pbt); - } - } - } - } + pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsan), PBUF_RAM); + if(pbt != NULL) { + uint8_t* dst = reinterpret_cast(pbt->payload); + memcpy(dst, (uint8_t *)&nbnsan, sizeof(nbnsan)); + udp_sendto(_pcb, pbt, &saddr, NBNS_PORT); + pbuf_free(pbt); + } + } + } + } - pbuf * this_pb = pb; - pb = pb->next; - this_pb->next = NULL; - pbuf_free(this_pb); - } + pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + pbuf_free(this_pb); + } } -void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, struct ip_addr *addr, uint16_t port){ - reinterpret_cast(arg)->_recv(upcb, p, addr, port); +void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, struct ip_addr *addr, uint16_t port) +{ + reinterpret_cast(arg)->_recv(upcb, p, addr, port); } ESP8266NetBIOS NBNS; diff --git a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h index 47c048ae29..d046b6c9fe 100755 --- a/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h +++ b/libraries/ESP8266NetBIOS/ESP8266NetBIOS.h @@ -19,14 +19,14 @@ struct ip_addr; class ESP8266NetBIOS { - protected: +protected: udp_pcb* _pcb; char _name[NBNS_MAX_HOSTNAME_LEN + 1]; void _getnbname(char *nbname, char *name, uint8_t maxlen); void _makenbname(char *name, char *nbname, uint8_t outlen); void _recv(udp_pcb *upcb, pbuf *pb, struct ip_addr *addr, uint16_t port); static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, struct ip_addr *addr, uint16_t port); - public: +public: ESP8266NetBIOS(); ~ESP8266NetBIOS(); bool begin(const char *name); diff --git a/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino b/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino index c3afe2fa7b..016439b0c1 100755 --- a/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino +++ b/libraries/ESP8266NetBIOS/examples/ESPNBNST/espnbnst.ino @@ -10,40 +10,40 @@ String content; static void handleRoot(void) { - content = F("\nHello world from ESP8266"); - content += F("

"); - content += F(""); + content = F("\nHello world from ESP8266"); + content += F("

"); + content += F(""); - wwwserver.send(200, F("text/html"), content); + wwwserver.send(200, F("text/html"), content); } void setup() { - Serial.begin(115200); + Serial.begin(115200); - // Connect to WiFi network - WiFi.begin(ssid, password); - Serial.println(""); + // Connect to WiFi network + WiFi.begin(ssid, password); + Serial.println(""); - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); - wwwserver.on("/", handleRoot); - wwwserver.begin(); + wwwserver.on("/", handleRoot); + wwwserver.begin(); - NBNS.begin("ESP"); + NBNS.begin("ESP"); } void loop() { - wwwserver.handleClient(); + wwwserver.handleClient(); }