dns_sd_misc.c
Go to the documentation of this file.
1 /**
2  * @file dns_sd_misc.c
3  * @brief Helper functions for DNS-SD
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL DNS_SD_TRACE_LEVEL
33 
34 //Dependencies
35 #include <stdlib.h>
36 #include "core/net.h"
37 #include "mdns/mdns_responder.h"
38 #include "dns_sd/dns_sd.h"
39 #include "dns_sd/dns_sd_misc.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (DNS_SD_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Update FSM state
48  * @param[in] context Pointer to the DNS-SD context
49  * @param[in] newState New state to switch to
50  * @param[in] delay Initial delay
51  **/
52 
53 void dnsSdChangeState(DnsSdContext *context, MdnsState newState,
54  systime_t delay)
55 {
56  NetInterface *interface;
57 
58  //Point to the underlying network interface
59  interface = context->settings.interface;
60 
61  //Set time stamp
62  context->timestamp = osGetSystemTime();
63  //Set initial delay
64  context->timeout = delay;
65  //Reset retransmission counter
66  context->retransmitCount = 0;
67  //Switch to the new state
68  context->state = newState;
69 
70  //Any registered callback?
71  if(context->settings.stateChangeEvent != NULL)
72  {
73  //Release exclusive access
75  //Invoke user callback function
76  context->settings.stateChangeEvent(context, interface, newState);
77  //Get exclusive access
79  }
80 }
81 
82 
83 /**
84  * @brief Programmatically change the service instance name
85  * @param[in] context Pointer to the DNS-SD context
86  **/
87 
89 {
90  size_t i;
91  size_t m;
92  size_t n;
93  uint32_t index;
94  char_t s[16];
95 
96  //Retrieve the length of the string
97  n = osStrlen(context->instanceName);
98 
99  //Parse the string backwards
100  for(i = n; i > 0; i--)
101  {
102  //Last character?
103  if(i == n)
104  {
105  //Check whether the last character is a bracket
106  if(context->instanceName[i - 1] != ')')
107  break;
108  }
109  else
110  {
111  //Check whether the current character is a digit
112  if(!osIsdigit(context->instanceName[i - 1]))
113  break;
114  }
115  }
116 
117  //Any number following the service instance name?
118  if(context->instanceName[i] != '\0')
119  {
120  //Retrieve the number at the end of the name
121  index = atoi(context->instanceName + i);
122  //Increment the value
123  index++;
124 
125  //Check the length of the name
126  if(i >= 2)
127  {
128  //Discard any space and bracket that may precede the number
129  if(context->instanceName[i - 2] == ' ' &&
130  context->instanceName[i - 1] == '(')
131  {
132  i -= 2;
133  }
134  }
135 
136  //Strip the digits
137  context->instanceName[i] = '\0';
138  }
139  else
140  {
141  //Append the digit "2" to the name
142  index = 2;
143  }
144 
145  //Convert the number to a string of characters
146  m = osSprintf(s, " (%" PRIu32 ")", index);
147 
148  //Sanity check
149  if((i + m) <= DNS_SD_MAX_INSTANCE_NAME_LEN)
150  {
151  //Programmatically change the service instance name
152  osStrcat(context->instanceName, s);
153  }
154 }
155 
156 
157 /**
158  * @brief Send probe packet
159  * @param[in] context Pointer to the DNS-SD context
160  * @return Error code
161  **/
162 
164 {
165  error_t error;
166  uint_t i;
167  NetInterface *interface;
168  DnsQuestion *dnsQuestion;
169  DnsSdService *service;
171 
172  //Point to the underlying network interface
173  interface = context->settings.interface;
174 
175  //Create an empty mDNS query message
176  error = mdnsCreateMessage(&message, FALSE);
177  //Any error to report?
178  if(error)
179  return error;
180 
181  //Start of exception handling block
182  do
183  {
184  //For all those resource records that a mDNS responder desires to be
185  //unique on the local link, it must send a mDNS query asking for those
186  //resource records, to see if any of them are already in use
187  if(dnsSdGetNumServices(context) > 0)
188  {
189  //Loop through the list of registered services
190  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
191  {
192  //Point to the current entry
193  service = &context->serviceList[i];
194 
195  //Valid service?
196  if(service->name[0] != '\0')
197  {
198  //Encode the service name using DNS notation
199  message.length += mdnsEncodeName(context->instanceName, service->name,
200  ".local", (uint8_t *) message.dnsHeader + message.length);
201 
202  //Point to the corresponding question structure
203  dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length);
204 
205  //The probes should be sent as QU questions with the unicast-response
206  //bit set, to allow a defending host to respond immediately via unicast
207  dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY);
208  dnsQuestion->qclass = HTONS(MDNS_QCLASS_QU | DNS_RR_CLASS_IN);
209 
210  //Update the length of the mDNS query message
211  message.length += sizeof(DnsQuestion);
212 
213  //Number of questions in the Question Section
214  message.dnsHeader->qdcount++;
215  }
216  }
217  }
218 
219  //A probe query can be distinguished from a normal query by the fact that
220  //a probe query contains a proposed record in the Authority Section that
221  //answers the question in the Question Section
222  if(dnsSdGetNumServices(context) > 0)
223  {
224  //Loop through the list of registered services
225  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
226  {
227  //Point to the current entry
228  service = &context->serviceList[i];
229 
230  //Valid service?
231  if(service->name[0] != '\0')
232  {
233  //Format SRV resource record
234  error = dnsSdFormatSrvRecord(interface, &message, service,
236  //Any error to report?
237  if(error)
238  break;
239 
240  //Format TXT resource record
241  error = dnsSdFormatTxtRecord(interface, &message, service,
243  //Any error to report?
244  if(error)
245  break;
246  }
247  }
248  }
249 
250  //Propagate exception if necessary
251  if(error)
252  break;
253 
254  //Number of resource records in the Authority Section
255  message.dnsHeader->nscount = message.dnsHeader->ancount;
256  //Number of resource records in the Answer Section
257  message.dnsHeader->ancount = 0;
258 
259  //Send mDNS message
260  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
261 
262  //End of exception handling block
263  } while(0);
264 
265  //Free previously allocated memory
267 
268  //Return status code
269  return error;
270 }
271 
272 
273 /**
274  * @brief Send announcement packet
275  * @param[in] context Pointer to the DNS-SD context
276  * @return Error code
277  **/
278 
280 {
281  error_t error;
282  uint_t i;
283  NetInterface *interface;
284  DnsSdService *service;
286 
287  //Point to the underlying network interface
288  interface = context->settings.interface;
289 
290  //Create an empty mDNS response message
291  error = mdnsCreateMessage(&message, TRUE);
292  //Any error to report?
293  if(error)
294  return error;
295 
296  //Start of exception handling block
297  do
298  {
299  //Send an unsolicited mDNS response containing, in the Answer Section,
300  //all of its newly registered resource records
301  if(dnsSdGetNumServices(context) > 0)
302  {
303  //Loop through the list of registered services
304  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
305  {
306  //Point to the current entry
307  service = &context->serviceList[i];
308 
309  //Valid service?
310  if(service->name[0] != '\0')
311  {
312  //Format PTR resource record (service type enumeration)
313  error = dnsSdFormatServiceEnumPtrRecord(interface, &message,
314  service, DNS_SD_DEFAULT_RR_TTL);
315  //Any error to report?
316  if(error)
317  break;
318 
319  //Format PTR resource record
320  error = dnsSdFormatPtrRecord(interface, &message, service,
322  //Any error to report?
323  if(error)
324  break;
325 
326  //Format SRV resource record
327  error = dnsSdFormatSrvRecord(interface, &message, service, TRUE,
329  //Any error to report?
330  if(error)
331  break;
332 
333  //Format TXT resource record
334  error = dnsSdFormatTxtRecord(interface, &message, service, TRUE,
336  //Any error to report?
337  if(error)
338  break;
339  }
340  }
341  }
342 
343  //Propagate exception if necessary
344  if(error)
345  break;
346 
347  //Send mDNS message
348  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
349 
350  //End of exception handling block
351  } while(0);
352 
353  //Free previously allocated memory
355 
356  //Return status code
357  return error;
358 }
359 
360 
361 /**
362  * @brief Send goodbye packet
363  * @param[in] context Pointer to the DNS-SD context
364  * @param[in] service Pointer to a DNS-SD service
365  * @return Error code
366  **/
367 
369 {
370  error_t error;
371  uint_t i;
372  NetInterface *interface;
373  DnsSdService *entry;
375 
376  //Point to the underlying network interface
377  interface = context->settings.interface;
378 
379  //Create an empty mDNS response message
380  error = mdnsCreateMessage(&message, TRUE);
381  //Any error to report?
382  if(error)
383  return error;
384 
385  //Loop through the list of registered services
386  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
387  {
388  //Point to the current entry
389  entry = &context->serviceList[i];
390 
391  //Valid service?
392  if(entry->name[0] != '\0')
393  {
394  if(service == entry || service == NULL)
395  {
396  //Format PTR resource record (service type enumeration)
397  error = dnsSdFormatServiceEnumPtrRecord(interface, &message, entry, 0);
398  //Any error to report?
399  if(error)
400  break;
401 
402  //Format PTR resource record
403  error = dnsSdFormatPtrRecord(interface, &message, entry, 0);
404  //Any error to report?
405  if(error)
406  break;
407 
408  //Format SRV resource record
409  error = dnsSdFormatSrvRecord(interface, &message, entry, TRUE, 0);
410  //Any error to report?
411  if(error)
412  break;
413 
414  //Format TXT resource record
415  error = dnsSdFormatTxtRecord(interface, &message, entry, TRUE, 0);
416  //Any error to report?
417  if(error)
418  break;
419  }
420  }
421  }
422 
423  //Check status code
424  if(!error)
425  {
426  //Send mDNS message
427  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
428  }
429 
430  //Free previously allocated memory
432 
433  //Return status code
434  return error;
435 }
436 
437 
438 /**
439  * @brief Parse a question
440  * @param[in] interface Underlying network interface
441  * @param[in] query Incoming mDNS query message
442  * @param[in] offset Offset to first byte of the question
443  * @param[in] question Pointer to the question
444  * @param[in,out] response mDNS response message
445  * @return Error code
446  **/
447 
449  size_t offset, const DnsQuestion *question, MdnsMessage *response)
450 {
451  error_t error;
452  uint_t i;
453  uint16_t qclass;
454  uint16_t qtype;
455  uint32_t ttl;
456  bool_t cacheFlush;
457  DnsSdContext *context;
458  DnsSdService *service;
459 
460  //Point to the DNS-SD context
461  context = interface->dnsSdContext;
462  //Make sure DNS-SD has been properly instantiated
463  if(context == NULL)
464  return NO_ERROR;
465 
466  //Check the state of the mDNS responder
467  if(context->state != MDNS_STATE_ANNOUNCING &&
468  context->state != MDNS_STATE_IDLE)
469  {
470  //Do not respond to mDNS queries during probing
471  return NO_ERROR;
472  }
473 
474  //Convert the query class to host byte order
475  qclass = ntohs(question->qclass);
476  //Discard QU flag
478 
479  //Convert the query type to host byte order
480  qtype = ntohs(question->qtype);
481 
482  //Get the TTL resource record
483  ttl = context->settings.ttl;
484 
485  //Check whether the querier originating the query is a simple resolver
486  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
487  {
488  //The resource record TTL given in a legacy unicast response should
489  //not be greater than ten seconds, even if the true TTL of the mDNS
490  //resource record is higher
492 
493  //The cache-flush bit must not be set in legacy unicast responses
494  cacheFlush = FALSE;
495  }
496  else
497  {
498  //The cache-bit should be set for unique resource records
499  cacheFlush = TRUE;
500  }
501 
502  //Any registered services?
503  if(dnsSdGetNumServices(context) > 0)
504  {
505  //Loop through the list of registered services
506  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
507  {
508  //Point to the current entry
509  service = &context->serviceList[i];
510 
511  //Valid service?
512  if(service->name[0] != '\0')
513  {
514  //Check the class of the query
516  {
517  //Compare service name
518  if(!mdnsCompareName(query->dnsHeader, query->length,
519  offset, "", "_services._dns-sd._udp", ".local", 0))
520  {
521  //PTR query?
522  if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
523  {
524  //Format PTR resource record (service type enumeration)
525  error = dnsSdFormatServiceEnumPtrRecord(interface,
526  response, service, ttl);
527  //Any error to report?
528  if(error)
529  return error;
530 
531  //Update the number of shared resource records
532  response->sharedRecordCount++;
533  }
534  }
535  else if(!mdnsCompareName(query->dnsHeader, query->length,
536  offset, "", service->name, ".local", 0))
537  {
538  //PTR query?
539  if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
540  {
541  //Format PTR resource record
542  error = dnsSdFormatPtrRecord(interface, response, service,
543  ttl);
544  //Any error to report?
545  if(error)
546  return error;
547 
548  //Update the number of shared resource records
549  response->sharedRecordCount++;
550  }
551  }
552  else if(!mdnsCompareName(query->dnsHeader, query->length, offset,
553  context->instanceName, service->name, ".local", 0))
554  {
555  //SRV query?
556  if(qtype == DNS_RR_TYPE_SRV || qtype == DNS_RR_TYPE_ANY)
557  {
558  //Format SRV resource record
559  error = dnsSdFormatSrvRecord(interface, response, service,
560  cacheFlush, ttl);
561  //Any error to report?
562  if(error)
563  return error;
564  }
565 
566  //TXT query?
567  if(qtype == DNS_RR_TYPE_TXT || qtype == DNS_RR_TYPE_ANY)
568  {
569  //Format TXT resource record
570  error = dnsSdFormatTxtRecord(interface, response, service,
571  cacheFlush, ttl);
572  //Any error to report?
573  if(error)
574  return error;
575  }
576 
577  //NSEC query?
578  if(qtype != DNS_RR_TYPE_SRV && qtype != DNS_RR_TYPE_TXT)
579  {
580  //Format NSEC resource record
581  error = dnsSdFormatNsecRecord(interface, response, service,
582  cacheFlush, ttl);
583  //Any error to report?
584  if(error)
585  return error;
586  }
587  }
588  }
589  }
590  }
591  }
592 
593  //Successful processing
594  return NO_ERROR;
595 }
596 
597 
598 /**
599  * @brief Parse a resource record from the Authority Section
600  * @param[in] interface Underlying network interface
601  * @param[in] query Incoming mDNS query message
602  * @param[in] offset Offset to first byte of the resource record
603  * @param[in] record Pointer to the resource record
604  **/
605 
606 void dnsSdParseNsRecord(NetInterface *interface, const MdnsMessage *query,
607  size_t offset, const DnsResourceRecord *record)
608 {
609  uint_t i;
610  uint16_t rclass;
611  DnsSdContext *context;
612  DnsSdService *service;
613  DnsSrvResourceRecord *srvRecord;
614 
615  //Point to the DNS-SD context
616  context = interface->dnsSdContext;
617  //Make sure DNS-SD has been properly instantiated
618  if(context == NULL)
619  return;
620 
621  //Any services registered?
622  if(dnsSdGetNumServices(context) > 0)
623  {
624  //Loop through the list of registered services
625  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
626  {
627  //Point to the current entry
628  service = &context->serviceList[i];
629 
630  //Valid service?
631  if(service->name[0] != '\0')
632  {
633  //Apply tie-breaking rules
634  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
635  context->instanceName, service->name, ".local", 0))
636  {
637  //Convert the class to host byte order
638  rclass = ntohs(record->rclass);
639  //Discard Cache Flush flag
641 
642  //Check the class of the resource record
643  if(rclass == DNS_RR_CLASS_IN)
644  {
645  //SRV resource record found?
646  if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
647  {
648  //Cast resource record
649  srvRecord = (DnsSrvResourceRecord *) record;
650 
651  //Compare Priority fields
652  if(ntohs(srvRecord->priority) > service->priority)
653  {
654  context->tieBreakLost = TRUE;
655  }
656  else if(ntohs(srvRecord->priority) == service->priority)
657  {
658  //Compare Weight fields
659  if(ntohs(srvRecord->weight) > service->weight)
660  {
661  context->tieBreakLost = TRUE;
662  }
663  else if(ntohs(srvRecord->weight) == service->weight)
664  {
665  //Compare Port fields
666  if(ntohs(srvRecord->port) > service->port)
667  {
668  context->tieBreakLost = TRUE;
669  }
670  else if(ntohs(srvRecord->port) == service->port)
671  {
672  //Compute the offset of the first byte of the target
673  offset = srvRecord->target - (uint8_t *) query->dnsHeader;
674 
675  if(mdnsCompareName(query->dnsHeader, query->length, offset,
676  context->instanceName, "", ".local", 0) > 0)
677  {
678  //The host has lost the tie-break
679  context->tieBreakLost = TRUE;
680  }
681  }
682  }
683  }
684  }
685  }
686  }
687  }
688  }
689  }
690 }
691 
692 
693 /**
694  * @brief Parse a resource record from the Answer Section
695  * @param[in] interface Underlying network interface
696  * @param[in] response Incoming mDNS response message
697  * @param[in] offset Offset to first byte of the resource record to be checked
698  * @param[in] record Pointer to the resource record
699  **/
700 
701 void dnsSdParseAnRecord(NetInterface *interface, const MdnsMessage *response,
702  size_t offset, const DnsResourceRecord *record)
703 {
704  uint_t i;
705  uint16_t rclass;
706  DnsSdContext *context;
707  DnsSdService *service;
708 
709  //Point to the DNS-SD context
710  context = interface->dnsSdContext;
711  //Make sure DNS-SD has been properly instantiated
712  if(context == NULL)
713  return;
714 
715  //Any services registered?
716  if(dnsSdGetNumServices(context) > 0)
717  {
718  //Loop through the list of registered services
719  for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++)
720  {
721  //Point to the current entry
722  service = &context->serviceList[i];
723 
724  //Valid service?
725  if(service->name[0] != '\0')
726  {
727  //Check for conflicts
728  if(!mdnsCompareName(response->dnsHeader, response->length, offset,
729  context->instanceName, service->name, ".local", 0))
730  {
731  //Convert the class to host byte order
732  rclass = ntohs(record->rclass);
733  //Discard Cache Flush flag
735 
736  //Check the class of the resource record
737  if(rclass == DNS_RR_CLASS_IN)
738  {
739  //SRV resource record found?
740  if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
741  {
742  //Compute the offset of the first byte of the rdata
743  offset = record->rdata - (uint8_t *) response->dnsHeader;
744 
745  //A conflict occurs when a mDNS responder has a unique record for
746  //which it is currently authoritative, and it receives a mDNS
747  //response message containing a record with the same name, rrtype
748  //and rrclass, but inconsistent rdata
749  if(mdnsCompareName(response->dnsHeader, response->length, offset,
750  context->instanceName, "", ".local", 0))
751  {
752  //The service instance name is already in use by some other host
753  context->conflict = TRUE;
754  }
755  }
756  }
757  }
758  }
759  }
760  }
761 }
762 
763 
764 /**
765  * @brief Additional record generation
766  * @param[in] interface Underlying network interface
767  * @param[in,out] response mDNS response message
768  * @param[in] legacyUnicast This flag is set for legacy unicast responses
769  **/
770 
772  MdnsMessage *response, bool_t legacyUnicast)
773 {
774  error_t error;
775  uint_t i;
776  uint_t j;
777  size_t n;
778  size_t offset;
779  uint_t ancount;
780  uint16_t rclass;
781  uint32_t ttl;
782  bool_t cacheFlush;
783  DnsSdContext *context;
784  DnsSdService *service;
785  DnsResourceRecord *record;
786 
787  //Point to the DNS-SD context
788  context = interface->dnsSdContext;
789  //Make sure DNS-SD has been properly instantiated
790  if(context == NULL)
791  return;
792 
793  //No registered services?
794  if(dnsSdGetNumServices(context) == 0)
795  return;
796 
797  //mDNS responses must not contain any questions in the Question Section
798  if(response->dnsHeader->qdcount != 0)
799  return;
800 
801  //Get the TTL resource record
802  ttl = context->settings.ttl;
803 
804  //Check whether the querier originating the query is a simple resolver
805  if(legacyUnicast)
806  {
807  //The resource record TTL given in a legacy unicast response should
808  //not be greater than ten seconds, even if the true TTL of the mDNS
809  //resource record is higher
811 
812  //The cache-flush bit must not be set in legacy unicast responses
813  cacheFlush = FALSE;
814  }
815  else
816  {
817  //The cache-bit should be set for unique resource records
818  cacheFlush = TRUE;
819  }
820 
821  //Point to the first resource record
822  offset = sizeof(DnsHeader);
823 
824  //Save the number of resource records in the Answer Section
825  ancount = response->dnsHeader->ancount;
826 
827  //Parse the Answer Section
828  for(i = 0; i < ancount; i++)
829  {
830  //Parse resource record name
831  n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
832  //Invalid name?
833  if(!n)
834  break;
835 
836  //Point to the associated resource record
837  record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
838  //Point to the resource data
839  n += sizeof(DnsResourceRecord);
840 
841  //Make sure the resource record is valid
842  if(n > response->length)
843  break;
844  if((n + ntohs(record->rdlength)) > response->length)
845  break;
846 
847  //Convert the record class to host byte order
848  rclass = ntohs(record->rclass);
849  //Discard the cache-flush bit
851 
852  //Loop through the list of registered services
853  for(j = 0; j < DNS_SD_SERVICE_LIST_SIZE; j++)
854  {
855  //Point to the current entry
856  service = &context->serviceList[j];
857 
858  //Valid service?
859  if(service->name[0] != '\0')
860  {
861  //Check the class of the resource record
862  if(rclass == DNS_RR_CLASS_IN)
863  {
864  //PTR record?
865  if(ntohs(record->rtype) == DNS_RR_TYPE_PTR)
866  {
867  //Compare service name
868  if(!mdnsCompareName(response->dnsHeader, response->length,
869  offset, "", service->name, ".local", 0))
870  {
871  //Format SRV resource record
872  error = dnsSdFormatSrvRecord(interface, response, service,
873  cacheFlush, ttl);
874  //Any error to report?
875  if(error)
876  return;
877 
878  //Format TXT resource record
879  error = dnsSdFormatTxtRecord(interface, response, service,
880  cacheFlush, ttl);
881  //Any error to report?
882  if(error)
883  return;
884  }
885  }
886  //SRV record?
887  else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
888  {
889  //Compare service name
890  if(!mdnsCompareName(response->dnsHeader, response->length,
891  offset, context->instanceName, service->name, ".local", 0))
892  {
893  //Format TXT resource record
894  error = dnsSdFormatTxtRecord(interface, response, service,
895  cacheFlush, ttl);
896  //Any error to report?
897  if(error)
898  return;
899  }
900  }
901  }
902  }
903  }
904 
905  //Point to the next resource record
906  offset = n + ntohs(record->rdlength);
907  }
908 
909  //Number of resource records in the Additional Section
910  response->dnsHeader->arcount += response->dnsHeader->ancount - ancount;
911  //Number of resource records in the Answer Section
912  response->dnsHeader->ancount = ancount;
913 }
914 
915 
916 /**
917  * @brief Format PTR resource record (in response to a meta-query)
918  * @param[in] interface Underlying network interface
919  * @param[in,out] message Pointer to the mDNS message
920  * @param[in] service Pointer to a DNS-SD service
921  * @param[in] ttl Resource record TTL (cache lifetime)
922  * @return Error code
923  **/
924 
926  MdnsMessage *message, const DnsSdService *service, uint32_t ttl)
927 {
928  size_t n;
929  size_t offset;
930  bool_t duplicate;
931  DnsResourceRecord *record;
932 
933  //Check whether the resource record is already present in the Answer
934  //Section of the message
935  duplicate = mdnsCheckDuplicateRecord(message, "", "_services._dns-sd._udp",
936  ".local", DNS_RR_TYPE_PTR, NULL, 0);
937 
938  //The duplicates should be suppressed and the resource record should
939  //appear only once in the list
940  if(!duplicate)
941  {
942  //Set the position to the end of the buffer
943  offset = message->length;
944 
945  //The first pass calculates the length of the DNS encoded service name
946  n = mdnsEncodeName("", "_services._dns-sd._udp", ".local", NULL);
947 
948  //Check the length of the resulting mDNS message
949  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
950  return ERROR_MESSAGE_TOO_LONG;
951 
952  //The second pass encodes the service name using the DNS name notation
953  offset += mdnsEncodeName("", "_services._dns-sd._udp", ".local",
954  (uint8_t *) message->dnsHeader + offset);
955 
956  //Consider the length of the resource record itself
957  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
958  return ERROR_MESSAGE_TOO_LONG;
959 
960  //Point to the corresponding resource record
961  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
962 
963  //Fill in resource record
964  record->rtype = HTONS(DNS_RR_TYPE_PTR);
965  record->rclass = HTONS(DNS_RR_CLASS_IN);
966  record->ttl = htonl(ttl);
967 
968  //Advance write index
969  offset += sizeof(DnsResourceRecord);
970 
971  //The first pass calculates the length of the DNS encoded service name
972  n = mdnsEncodeName("", service->name, ".local", NULL);
973 
974  //Check the length of the resulting mDNS message
975  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
976  return ERROR_MESSAGE_TOO_LONG;
977 
978  //The second pass encodes the service name using DNS notation
979  n = mdnsEncodeName("", service->name, ".local", record->rdata);
980 
981  //Convert length field to network byte order
982  record->rdlength = htons(n);
983 
984  //Number of resource records in the answer section
985  message->dnsHeader->ancount++;
986  //Update the length of the DNS message
987  message->length = offset + n;
988  }
989 
990  //Successful processing
991  return NO_ERROR;
992 }
993 
994 
995 /**
996  * @brief Format PTR resource record
997  * @param[in] interface Underlying network interface
998  * @param[in,out] message Pointer to the mDNS message
999  * @param[in] service Pointer to a DNS-SD service
1000  * @param[in] ttl Resource record TTL (cache lifetime)
1001  * @return Error code
1002  **/
1003 
1005  const DnsSdService *service, uint32_t ttl)
1006 {
1007  size_t n;
1008  size_t offset;
1009  bool_t duplicate;
1010  DnsSdContext *context;
1011  DnsResourceRecord *record;
1012 
1013  //Point to the DNS-SD context
1014  context = interface->dnsSdContext;
1015 
1016  //Check whether the resource record is already present in the Answer
1017  //Section of the message
1018  duplicate = mdnsCheckDuplicateRecord(message, "", service->name, ".local",
1019  DNS_RR_TYPE_PTR, NULL, 0);
1020 
1021  //The duplicates should be suppressed and the resource record should
1022  //appear only once in the list
1023  if(!duplicate)
1024  {
1025  //Set the position to the end of the buffer
1026  offset = message->length;
1027 
1028  //The first pass calculates the length of the DNS encoded service name
1029  n = mdnsEncodeName("", service->name, ".local", NULL);
1030 
1031  //Check the length of the resulting mDNS message
1032  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1033  return ERROR_MESSAGE_TOO_LONG;
1034 
1035  //The second pass encodes the service name using the DNS name notation
1036  offset += mdnsEncodeName("", service->name, ".local",
1037  (uint8_t *) message->dnsHeader + offset);
1038 
1039  //Consider the length of the resource record itself
1040  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1041  return ERROR_MESSAGE_TOO_LONG;
1042 
1043  //Point to the corresponding resource record
1044  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1045 
1046  //Fill in resource record
1047  record->rtype = HTONS(DNS_RR_TYPE_PTR);
1048  record->rclass = HTONS(DNS_RR_CLASS_IN);
1049  record->ttl = htonl(ttl);
1050 
1051  //Advance write index
1052  offset += sizeof(DnsResourceRecord);
1053 
1054  //The first pass calculates the length of the DNS encoded instance name
1055  n = mdnsEncodeName(context->instanceName, service->name, ".local", NULL);
1056 
1057  //Check the length of the resulting mDNS message
1058  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1059  return ERROR_MESSAGE_TOO_LONG;
1060 
1061  //The second pass encodes the instance name using DNS notation
1062  n = mdnsEncodeName(context->instanceName, service->name, ".local",
1063  record->rdata);
1064 
1065  //Convert length field to network byte order
1066  record->rdlength = htons(n);
1067 
1068  //Number of resource records in the answer section
1069  message->dnsHeader->ancount++;
1070  //Update the length of the DNS message
1071  message->length = offset + n;
1072  }
1073 
1074  //Successful processing
1075  return NO_ERROR;
1076 }
1077 
1078 
1079 /**
1080  * @brief Format SRV resource record
1081  * @param[in] interface Underlying network interface
1082  * @param[in,out] message Pointer to the mDNS message
1083  * @param[in] service Pointer to a DNS-SD service
1084  * @param[in] cacheFlush Cache-flush bit
1085  * @param[in] ttl Resource record TTL (cache lifetime)
1086  * @return Error code
1087  **/
1088 
1090  const DnsSdService *service, bool_t cacheFlush, uint32_t ttl)
1091 {
1092  size_t n;
1093  size_t offset;
1094  bool_t duplicate;
1095  MdnsResponderContext *mdnsResponderContext;
1096  DnsSdContext *dnsSdContext;
1097  DnsSrvResourceRecord *record;
1098 
1099  //Point to the mDNS responder context
1100  mdnsResponderContext = interface->mdnsResponderContext;
1101  //Point to the DNS-SD context
1102  dnsSdContext = interface->dnsSdContext;
1103 
1104  //Check whether the resource record is already present in the Answer
1105  //Section of the message
1106  duplicate = mdnsCheckDuplicateRecord(message, dnsSdContext->instanceName,
1107  service->name, ".local", DNS_RR_TYPE_SRV, NULL, 0);
1108 
1109  //The duplicates should be suppressed and the resource record should
1110  //appear only once in the list
1111  if(!duplicate)
1112  {
1113  //Set the position to the end of the buffer
1114  offset = message->length;
1115 
1116  //The first pass calculates the length of the DNS encoded instance name
1117  n = mdnsEncodeName(dnsSdContext->instanceName, service->name, ".local",
1118  NULL);
1119 
1120  //Check the length of the resulting mDNS message
1121  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1122  return ERROR_MESSAGE_TOO_LONG;
1123 
1124  //The second pass encodes the instance name using DNS notation
1125  offset += mdnsEncodeName(dnsSdContext->instanceName, service->name, ".local",
1126  (uint8_t *) message->dnsHeader + offset);
1127 
1128  //Consider the length of the resource record itself
1129  if((offset + sizeof(DnsSrvResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1130  return ERROR_MESSAGE_TOO_LONG;
1131 
1132  //Point to the corresponding resource record
1133  record = (DnsSrvResourceRecord *) DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1134 
1135  //Fill in resource record
1136  record->rtype = HTONS(DNS_RR_TYPE_SRV);
1137  record->rclass = HTONS(DNS_RR_CLASS_IN);
1138  record->ttl = htonl(ttl);
1139  record->priority = htons(service->priority);
1140  record->weight = htons(service->weight);
1141  record->port = htons(service->port);
1142 
1143  //Check whether the cache-flush bit should be set
1144  if(cacheFlush)
1145  {
1146  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1147  }
1148 
1149  //Advance write index
1150  offset += sizeof(DnsSrvResourceRecord);
1151 
1152  //The first pass calculates the length of the DNS encoded target name
1153  n = mdnsEncodeName("", mdnsResponderContext->hostname, ".local", NULL);
1154 
1155  //Check the length of the resulting mDNS message
1156  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1157  return ERROR_MESSAGE_TOO_LONG;
1158 
1159  //The second pass encodes the target name using DNS notation
1160  n = mdnsEncodeName("", mdnsResponderContext->hostname, ".local",
1161  record->target);
1162 
1163  //Calculate data length
1164  record->rdlength = htons(sizeof(DnsSrvResourceRecord) -
1165  sizeof(DnsResourceRecord) + n);
1166 
1167  //Number of resource records in the answer section
1168  message->dnsHeader->ancount++;
1169  //Update the length of the DNS message
1170  message->length = offset + n;
1171  }
1172 
1173  //Successful processing
1174  return NO_ERROR;
1175 }
1176 
1177 
1178 /**
1179  * @brief Format TXT resource record
1180  * @param[in] interface Underlying network interface
1181  * @param[in,out] message Pointer to the mDNS message
1182  * @param[in] service Pointer to a DNS-SD service
1183  * @param[in] cacheFlush Cache-flush bit
1184  * @param[in] ttl Resource record TTL (cache lifetime)
1185  * @return Error code
1186  **/
1187 
1189  const DnsSdService *service, bool_t cacheFlush, uint32_t ttl)
1190 {
1191  size_t n;
1192  size_t offset;
1193  bool_t duplicate;
1194  DnsSdContext *context;
1195  DnsResourceRecord *record;
1196 
1197  //Point to the DNS-SD context
1198  context = interface->dnsSdContext;
1199 
1200  //Check whether the resource record is already present in the Answer
1201  //Section of the message
1202  duplicate = mdnsCheckDuplicateRecord(message, context->instanceName,
1203  service->name, ".local", DNS_RR_TYPE_TXT, NULL, 0);
1204 
1205  //The duplicates should be suppressed and the resource record should
1206  //appear only once in the list
1207  if(!duplicate)
1208  {
1209  //Set the position to the end of the buffer
1210  offset = message->length;
1211 
1212  //The first pass calculates the length of the DNS encoded instance name
1213  n = mdnsEncodeName(context->instanceName, service->name, ".local", NULL);
1214 
1215  //Check the length of the resulting mDNS message
1216  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1217  return ERROR_MESSAGE_TOO_LONG;
1218 
1219  //The second pass encodes the instance name using DNS notation
1220  offset += mdnsEncodeName(context->instanceName, service->name, ".local",
1221  (uint8_t *) message->dnsHeader + offset);
1222 
1223  //Consider the length of the resource record itself
1224  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1225  return ERROR_MESSAGE_TOO_LONG;
1226 
1227  //Point to the corresponding resource record
1228  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1229 
1230  //Fill in resource record
1231  record->rtype = HTONS(DNS_RR_TYPE_TXT);
1232  record->rclass = HTONS(DNS_RR_CLASS_IN);
1233  record->ttl = htonl(ttl);
1234  record->rdlength = htons(service->metadataLength);
1235 
1236  //Check whether the cache-flush bit should be set
1237  if(cacheFlush)
1238  {
1239  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1240  }
1241 
1242  //Advance write index
1243  offset += sizeof(DnsResourceRecord);
1244 
1245  //Check the length of the resulting mDNS message
1246  if((offset + service->metadataLength) > MDNS_MESSAGE_MAX_SIZE)
1247  return ERROR_MESSAGE_TOO_LONG;
1248 
1249  //Copy metadata
1250  osMemcpy(record->rdata, service->metadata, service->metadataLength);
1251 
1252  //Update the length of the DNS message
1253  message->length = offset + service->metadataLength;
1254  //Number of resource records in the answer section
1255  message->dnsHeader->ancount++;
1256  }
1257 
1258  //Successful processing
1259  return NO_ERROR;
1260 }
1261 
1262 
1263 /**
1264  * @brief Format NSEC resource record
1265  * @param[in] interface Underlying network interface
1266  * @param[in,out] message Pointer to the mDNS message
1267  * @param[in] service Pointer to a DNS-SD service
1268  * @param[in] cacheFlush Cache-flush bit
1269  * @param[in] ttl Resource record TTL (cache lifetime)
1270  * @return Error code
1271  **/
1272 
1274  const DnsSdService *service, bool_t cacheFlush, uint32_t ttl)
1275 {
1276  size_t n;
1277  size_t offset;
1278  bool_t duplicate;
1279  size_t bitmapLength;
1280  uint8_t bitmap[8];
1281  DnsSdContext *context;
1282  DnsResourceRecord *record;
1283 
1284  //Point to the DNS-SD context
1285  context = interface->dnsSdContext;
1286 
1287  //Check whether the resource record is already present in the Answer
1288  //Section of the message
1289  duplicate = mdnsCheckDuplicateRecord(message, context->instanceName,
1290  service->name, ".local", DNS_RR_TYPE_NSEC, NULL, 0);
1291 
1292  //The duplicates should be suppressed and the resource record should
1293  //appear only once in the list
1294  if(!duplicate)
1295  {
1296  //The bitmap identifies the resource record types that exist
1297  osMemset(bitmap, 0, sizeof(bitmap));
1298 
1299  //TXT resource record is supported
1301  //SRV resource record is supported
1303 
1304  //Compute the length of the bitmap
1305  for(bitmapLength = sizeof(bitmap); bitmapLength > 0; bitmapLength--)
1306  {
1307  //Trailing zero octets in the bitmap must be omitted...
1308  if(bitmap[bitmapLength - 1] != 0x00)
1309  break;
1310  }
1311 
1312  //Set the position to the end of the buffer
1313  offset = message->length;
1314 
1315  //The first pass calculates the length of the DNS encoded instance name
1316  n = mdnsEncodeName(context->instanceName, service->name, ".local", NULL);
1317 
1318  //Check the length of the resulting mDNS message
1319  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1320  return ERROR_MESSAGE_TOO_LONG;
1321 
1322  //The second pass encodes the instance name using the DNS name notation
1323  offset += mdnsEncodeName(context->instanceName, service->name,
1324  ".local", (uint8_t *) message->dnsHeader + offset);
1325 
1326  //Consider the length of the resource record itself
1327  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1328  return ERROR_MESSAGE_TOO_LONG;
1329 
1330  //Point to the corresponding resource record
1331  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1332 
1333  //Fill in resource record
1334  record->rtype = HTONS(DNS_RR_TYPE_NSEC);
1335  record->rclass = HTONS(DNS_RR_CLASS_IN);
1336  record->ttl = htonl(ttl);
1337 
1338  //Check whether the cache-flush bit should be set
1339  if(cacheFlush)
1340  {
1341  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1342  }
1343 
1344  //Advance write index
1345  offset += sizeof(DnsResourceRecord);
1346 
1347  //Check the length of the resulting mDNS message
1348  if((offset + n + 2) > MDNS_MESSAGE_MAX_SIZE)
1349  return ERROR_MESSAGE_TOO_LONG;
1350 
1351  //The Next Domain Name field contains the record's own name
1352  mdnsEncodeName(context->instanceName, service->name,
1353  ".local", record->rdata);
1354 
1355  //DNS NSEC record is limited to Window Block number zero
1356  record->rdata[n++] = 0;
1357  //The Bitmap Length is a value in the range 1-32
1358  record->rdata[n++] = bitmapLength;
1359 
1360  //The Bitmap data identifies the resource record types that exist
1361  osMemcpy(record->rdata + n, bitmap, bitmapLength);
1362 
1363  //Convert length field to network byte order
1364  record->rdlength = htons(n + bitmapLength);
1365 
1366  //Number of resource records in the answer section
1367  message->dnsHeader->ancount++;
1368  //Update the length of the DNS message
1369  message->length = offset + n + bitmapLength;
1370  }
1371 
1372  //Successful processing
1373  return NO_ERROR;
1374 }
1375 
1376 #endif
uint8_t message[]
Definition: chap.h:154
unsigned int uint_t
Definition: compiler_port.h:50
char char_t
Definition: compiler_port.h:48
int bool_t
Definition: compiler_port.h:53
#define HTONS(value)
Definition: cpu_endian.h:410
#define htonl(value)
Definition: cpu_endian.h:414
#define htons(value)
Definition: cpu_endian.h:413
#define ntohs(value)
Definition: cpu_endian.h:421
Debugging facilities.
uint8_t n
size_t dnsParseName(const DnsHeader *message, size_t length, size_t pos, char_t *dest, uint_t level)
Decode a domain name that uses the DNS name encoding.
Definition: dns_common.c:132
#define DNS_SET_NSEC_BITMAP(bitmap, type)
Definition: dns_common.h:66
DnsSrvResourceRecord
Definition: dns_common.h:269
uint16_t ancount
Definition: dns_common.h:195
DnsHeader
Definition: dns_common.h:199
uint32_t ttl
Definition: dns_common.h:221
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
DnsResourceRecord
Definition: dns_common.h:224
#define DNS_GET_QUESTION(message, offset)
Definition: dns_common.h:63
@ DNS_RR_TYPE_PTR
Domain name pointer.
Definition: dns_common.h:142
@ DNS_RR_TYPE_SRV
Server selection.
Definition: dns_common.h:149
@ DNS_RR_TYPE_TXT
Text strings.
Definition: dns_common.h:146
@ DNS_RR_TYPE_ANY
A request for all records.
Definition: dns_common.h:155
@ DNS_RR_TYPE_NSEC
NSEC record.
Definition: dns_common.h:151
@ DNS_RR_CLASS_ANY
Any class.
Definition: dns_common.h:127
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:124
DnsQuestion
Definition: dns_common.h:210
uint16_t rclass
Definition: dns_common.h:220
uint16_t qclass
Definition: dns_common.h:209
uint_t dnsSdGetNumServices(DnsSdContext *context)
Get the number of registered services.
Definition: dns_sd.c:456
DNS-SD (DNS-Based Service Discovery)
#define DNS_SD_SERVICE_LIST_SIZE
Definition: dns_sd.h:55
#define DnsSdContext
Definition: dns_sd.h:90
#define DNS_SD_DEFAULT_RR_TTL
Definition: dns_sd.h:83
#define DNS_SD_MAX_INSTANCE_NAME_LEN
Definition: dns_sd.h:69
error_t dnsSdParseQuestion(NetInterface *interface, const MdnsMessage *query, size_t offset, const DnsQuestion *question, MdnsMessage *response)
Parse a question.
Definition: dns_sd_misc.c:448
void dnsSdChangeInstanceName(DnsSdContext *context)
Programmatically change the service instance name.
Definition: dns_sd_misc.c:88
void dnsSdChangeState(DnsSdContext *context, MdnsState newState, systime_t delay)
Update FSM state.
Definition: dns_sd_misc.c:53
error_t dnsSdSendGoodbye(DnsSdContext *context, const DnsSdService *service)
Send goodbye packet.
Definition: dns_sd_misc.c:368
error_t dnsSdFormatTxtRecord(NetInterface *interface, MdnsMessage *message, const DnsSdService *service, bool_t cacheFlush, uint32_t ttl)
Format TXT resource record.
Definition: dns_sd_misc.c:1188
error_t dnsSdFormatServiceEnumPtrRecord(NetInterface *interface, MdnsMessage *message, const DnsSdService *service, uint32_t ttl)
Format PTR resource record (in response to a meta-query)
Definition: dns_sd_misc.c:925
error_t dnsSdSendAnnouncement(DnsSdContext *context)
Send announcement packet.
Definition: dns_sd_misc.c:279
void dnsSdParseAnRecord(NetInterface *interface, const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
Definition: dns_sd_misc.c:701
void dnsSdGenerateAdditionalRecords(NetInterface *interface, MdnsMessage *response, bool_t legacyUnicast)
Additional record generation.
Definition: dns_sd_misc.c:771
error_t dnsSdFormatPtrRecord(NetInterface *interface, MdnsMessage *message, const DnsSdService *service, uint32_t ttl)
Format PTR resource record.
Definition: dns_sd_misc.c:1004
void dnsSdParseNsRecord(NetInterface *interface, const MdnsMessage *query, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Authority Section.
Definition: dns_sd_misc.c:606
error_t dnsSdFormatSrvRecord(NetInterface *interface, MdnsMessage *message, const DnsSdService *service, bool_t cacheFlush, uint32_t ttl)
Format SRV resource record.
Definition: dns_sd_misc.c:1089
error_t dnsSdFormatNsecRecord(NetInterface *interface, MdnsMessage *message, const DnsSdService *service, bool_t cacheFlush, uint32_t ttl)
Format NSEC resource record.
Definition: dns_sd_misc.c:1273
error_t dnsSdSendProbe(DnsSdContext *context)
Send probe packet.
Definition: dns_sd_misc.c:163
Helper functions for DNS-SD.
error_t
Error codes.
Definition: error.h:43
@ ERROR_MESSAGE_TOO_LONG
Definition: error.h:136
@ NO_ERROR
Success.
Definition: error.h:44
void mdnsDeleteMessage(MdnsMessage *message)
release a mDNS message
Definition: mdns_common.c:433
error_t mdnsCreateMessage(MdnsMessage *message, bool_t queryResponse)
Create an empty mDNS message.
Definition: mdns_common.c:357
size_t mdnsEncodeName(const char_t *instance, const char_t *service, const char_t *domain, uint8_t *dest)
Encode instance, service and domain names using the DNS name notation.
Definition: mdns_common.c:543
bool_t mdnsCheckDuplicateRecord(const MdnsMessage *message, const char_t *instance, const char_t *service, const char_t *domain, uint16_t rtype, const uint8_t *rdata, size_t rdlength)
Check for duplicate resource records.
Definition: mdns_common.c:920
int_t mdnsCompareName(const DnsHeader *message, size_t length, size_t pos, const char_t *instance, const char_t *service, const char_t *domain, uint_t level)
Compare instance, service and domain names.
Definition: mdns_common.c:647
error_t mdnsSendMessage(NetInterface *interface, const MdnsMessage *message, const IpAddr *destIpAddr, uint_t destPort)
Send mDNS message.
Definition: mdns_common.c:457
#define MDNS_LEGACY_UNICAST_RR_TTL
Definition: mdns_common.h:57
#define MDNS_PORT
Definition: mdns_common.h:53
#define MDNS_MESSAGE_MAX_SIZE
Definition: mdns_common.h:40
#define MDNS_QCLASS_QU
Definition: mdns_common.h:60
#define MDNS_RCLASS_CACHE_FLUSH
Definition: mdns_common.h:62
mDNS responder (Multicast DNS)
#define MdnsResponderContext
MdnsState
mDNS responder states
@ MDNS_STATE_ANNOUNCING
@ MDNS_STATE_IDLE
uint8_t s
Definition: ndp.h:345
uint8_t m
Definition: ndp.h:304
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netMutex
Definition: net_legacy.h:195
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define osStrlen(s)
Definition: os_port.h:165
#define osSprintf(dest,...)
Definition: os_port.h:231
#define osIsdigit(c)
Definition: os_port.h:279
#define osStrcat(s1, s2)
Definition: os_port.h:219
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t systime_t
System time.
DNS-SD service descriptor.
Definition: dns_sd.h:124
uint16_t priority
Priority of the target host.
Definition: dns_sd.h:126
uint16_t weight
Server selection mechanism.
Definition: dns_sd.h:127
uint8_t metadata[DNS_SD_MAX_METADATA_LEN]
Discovery-time metadata (TXT record)
Definition: dns_sd.h:129
size_t metadataLength
Length of the metadata.
Definition: dns_sd.h:130
uint16_t port
Port on the target host of this service.
Definition: dns_sd.h:128
char_t name[DNS_SD_MAX_SERVICE_NAME_LEN+1]
Service name.
Definition: dns_sd.h:125
mDNS message
Definition: mdns_common.h:78
uint_t sharedRecordCount
Definition: mdns_common.h:87
const UdpHeader * udpHeader
Definition: mdns_common.h:83
size_t length
Definition: mdns_common.h:81
DnsHeader * dnsHeader
Definition: mdns_common.h:84