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