dns_sd_responder_misc.c
Go to the documentation of this file.
1 /**
2  * @file dns_sd_responder_misc.c
3  * @brief Helper functions for DNS-SD responder
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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL DNS_SD_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "mdns/mdns_responder.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (DNS_SD_RESPONDER_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Update FSM state
47  * @param[in] service Pointer to a DNS-SD service
48  * @param[in] newState New state to switch to
49  * @param[in] delay Initial delay
50  **/
51 
53  MdnsState newState, systime_t delay)
54 {
55  DnsSdResponderContext *context;
56 
57  //Point to the DNS-SD responder context
58  context = service->context;
59 
60  //Set time stamp
61  service->timestamp = osGetSystemTime();
62  //Set initial delay
63  service->timeout = delay;
64  //Reset retransmission counter
65  service->retransmitCount = 0;
66  //Switch to the new state
67  service->state = newState;
68 
69  //Any registered callback?
70  if(context->stateChangeEvent != NULL)
71  {
72  //Release exclusive access
74  //Invoke user callback function
75  context->stateChangeEvent(service, context->interface, newState);
76  //Get exclusive access
78  }
79 }
80 
81 
82 /**
83  * @brief Programmatically change the service instance name
84  * @param[in] service Pointer to a DNS-SD service
85  **/
86 
88 {
89  size_t i;
90  size_t m;
91  size_t n;
92  uint32_t index;
93  char_t s[16];
94 
95  //Retrieve the length of the string
96  n = osStrlen(service->instanceName);
97 
98  //Parse the string backwards
99  for(i = n; i > 0; i--)
100  {
101  //Last character?
102  if(i == n)
103  {
104  //Check whether the last character is a bracket
105  if(service->instanceName[i - 1] != ')')
106  break;
107  }
108  else
109  {
110  //Check whether the current character is a digit
111  if(!osIsdigit(service->instanceName[i - 1]))
112  break;
113  }
114  }
115 
116  //Any number following the service instance name?
117  if(service->instanceName[i] != '\0')
118  {
119  //Retrieve the number at the end of the name
120  index = osAtoi(service->instanceName + i);
121  //Increment the value
122  index++;
123 
124  //Check the length of the name
125  if(i >= 2)
126  {
127  //Discard any space and bracket that may precede the number
128  if(service->instanceName[i - 2] == ' ' &&
129  service->instanceName[i - 1] == '(')
130  {
131  i -= 2;
132  }
133  }
134 
135  //Strip the digits
136  service->instanceName[i] = '\0';
137  }
138  else
139  {
140  //Append the digit "2" to the name
141  index = 2;
142  }
143 
144  //Convert the number to a string of characters
145  m = osSprintf(s, " (%" PRIu32 ")", index);
146 
147  //Sanity check
148  if((i + m) <= DNS_SD_MAX_INSTANCE_NAME_LEN)
149  {
150  //Programmatically change the service instance name
151  osStrcat(service->instanceName, s);
152  }
153 }
154 
155 
156 /**
157  * @brief Send probe packet
158  * @param[in] service Pointer to a DNS-SD service
159  * @return Error code
160  **/
161 
163 {
164  error_t error;
165  DnsSdResponderContext *context;
166  NetInterface *interface;
167  DnsQuestion *dnsQuestion;
169 
170  //Point to the DNS-SD responder context
171  context = service->context;
172  //Point to the underlying network interface
173  interface = context->interface;
174 
175  //For all those resource records that a mDNS responder desires to be unique
176  //on the local link, it must send a mDNS query asking for those resource
177  //records, to see if any of them are already in use
178  error = mdnsCreateMessage(&message, FALSE);
179  //Any error to report?
180  if(error)
181  return error;
182 
183  //Start of exception handling block
184  do
185  {
186  //Encode the service name using DNS notation
187  message.length += mdnsEncodeName(service->instanceName,
188  service->serviceName, ".local",
189  (uint8_t *) message.dnsHeader + message.length);
190 
191  //Point to the corresponding question structure
192  dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length);
193 
194  //The probes should be sent as QU questions with the unicast-response
195  //bit set, to allow a defending host to respond immediately via unicast
196  dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY);
197  dnsQuestion->qclass = HTONS(MDNS_QCLASS_QU | DNS_RR_CLASS_IN);
198 
199  //Update the length of the mDNS query message
200  message.length += sizeof(DnsQuestion);
201 
202  //Number of questions in the Question Section
203  message.dnsHeader->qdcount++;
204 
205  //Format SRV resource record
206  error = dnsSdResponderFormatSrvRecord(interface, &message, service,
208  //Any error to report?
209  if(error)
210  break;
211 
212  //Format TXT resource record
213  error = dnsSdResponderFormatTxtRecord(interface, &message, service,
215  //Any error to report?
216  if(error)
217  break;
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  message.dnsHeader->nscount = message.dnsHeader->ancount;
223  message.dnsHeader->ancount = 0;
224 
225  //Send mDNS message
226  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
227 
228  //End of exception handling block
229  } while(0);
230 
231  //Free previously allocated memory
233 
234  //Return status code
235  return error;
236 }
237 
238 
239 /**
240  * @brief Send announcement packet
241  * @param[in] service Pointer to a DNS-SD service
242  * @return Error code
243  **/
244 
246 {
247  error_t error;
248  DnsSdResponderContext *context;
249  NetInterface *interface;
251 
252  //Point to the DNS-SD responder context
253  context = service->context;
254  //Point to the underlying network interface
255  interface = context->interface;
256 
257  //Send an unsolicited mDNS response containing, in the Answer Section, all
258  //of its newly registered resource records
259  error = mdnsCreateMessage(&message, TRUE);
260  //Any error to report?
261  if(error)
262  return error;
263 
264  //Start of exception handling block
265  do
266  {
267  //Format PTR resource record (service type enumeration)
269  service, DNS_SD_DEFAULT_RR_TTL);
270  //Any error to report?
271  if(error)
272  break;
273 
274  //Format PTR resource record
275  error = dnsSdResponderFormatPtrRecord(interface, &message, service,
277  //Any error to report?
278  if(error)
279  break;
280 
281  //Format SRV resource record
282  error = dnsSdResponderFormatSrvRecord(interface, &message, service, TRUE,
284  //Any error to report?
285  if(error)
286  break;
287 
288  //Format TXT resource record
289  error = dnsSdResponderFormatTxtRecord(interface, &message, service, TRUE,
291  //Any error to report?
292  if(error)
293  break;
294 
295  //Send mDNS message
296  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
297 
298  //End of exception handling block
299  } while(0);
300 
301  //Free previously allocated memory
303 
304  //Return status code
305  return error;
306 }
307 
308 
309 /**
310  * @brief Send goodbye packet
311  * @param[in] service Pointer to a DNS-SD service
312  * @return Error code
313  **/
314 
316 {
317  error_t error;
318  DnsSdResponderContext *context;
319  NetInterface *interface;
321 
322  //Point to the DNS-SD responder context
323  context = service->context;
324  //Point to the underlying network interface
325  interface = context->interface;
326 
327  //Create an empty mDNS response message
328  error = mdnsCreateMessage(&message, TRUE);
329  //Any error to report?
330  if(error)
331  return error;
332 
333  //Start of exception handling block
334  do
335  {
336  //Format PTR resource record (service type enumeration)
338  service, 0);
339  //Any error to report?
340  if(error)
341  break;
342 
343  //Format PTR resource record
344  error = dnsSdResponderFormatPtrRecord(interface, &message, service, 0);
345  //Any error to report?
346  if(error)
347  break;
348 
349  //Format SRV resource record
350  error = dnsSdResponderFormatSrvRecord(interface, &message, service,
351  TRUE, 0);
352  //Any error to report?
353  if(error)
354  break;
355 
356  //Format TXT resource record
357  error = dnsSdResponderFormatTxtRecord(interface, &message, service,
358  TRUE, 0);
359  //Any error to report?
360  if(error)
361  break;
362 
363  //Send mDNS message
364  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
365 
366  //End of exception handling block
367  } while(0);
368 
369  //Free previously allocated memory
371 
372  //Return status code
373  return error;
374 }
375 
376 
377 /**
378  * @brief Parse a question
379  * @param[in] interface Underlying network interface
380  * @param[in] query Incoming mDNS query message
381  * @param[in] offset Offset to first byte of the question
382  * @param[in] question Pointer to the question
383  * @param[in,out] response mDNS response message
384  * @return Error code
385  **/
386 
388  const MdnsMessage *query, size_t offset, const DnsQuestion *question,
389  MdnsMessage *response)
390 {
391  error_t error;
392  uint_t i;
393  uint16_t qclass;
394  uint16_t qtype;
395  uint32_t ttl;
396  bool_t cacheFlush;
397  DnsSdResponderContext *context;
398  DnsSdResponderService *service;
399 
400  //Point to the DNS-SD responder context
401  context = interface->dnsSdResponderContext;
402  //Make sure the DNS-SD responder has been properly instantiated
403  if(context == NULL)
404  return NO_ERROR;
405 
406  //Convert the query class to host byte order
407  qclass = ntohs(question->qclass);
408  //Discard QU flag
410 
411  //Convert the query type to host byte order
412  qtype = ntohs(question->qtype);
413 
414  //Get the TTL resource record
415  ttl = context->ttl;
416 
417  //Check whether the querier originating the query is a simple resolver
418  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
419  {
420  //The resource record TTL given in a legacy unicast response should not
421  //be greater than ten seconds, even if the true TTL of the mDNS resource
422  //record is higher
424 
425  //The cache-flush bit must not be set in legacy unicast responses
426  cacheFlush = FALSE;
427  }
428  else
429  {
430  //The cache-bit should be set for unique resource records
431  cacheFlush = TRUE;
432  }
433 
434  //Loop through the list of registered services
435  for(i = 0; i < context->numServices; i++)
436  {
437  //Point to the current entry
438  service = &context->services[i];
439 
440  //Valid service?
441  if(service->instanceName[0] != '\0' &&
442  service->serviceName[0] != '\0' &&
443  service->state != MDNS_STATE_INIT &&
444  service->state != MDNS_STATE_WAITING &&
445  service->state != MDNS_STATE_PROBING)
446  {
447  //Check the class of the query
449  {
450  //Compare service name
451  if(!mdnsCompareName(query->dnsHeader, query->length,
452  offset, "", "_services._dns-sd._udp", ".local", 0))
453  {
454  //PTR query?
455  if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
456  {
457  //Format PTR resource record (service type enumeration)
459  response, service, ttl);
460  //Any error to report?
461  if(error)
462  return error;
463 
464  //Update the number of shared resource records
465  response->sharedRecordCount++;
466  }
467  }
468  else if(!mdnsCompareName(query->dnsHeader, query->length,
469  offset, "", service->serviceName, ".local", 0))
470  {
471  //PTR query?
472  if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
473  {
474  //Format PTR resource record
475  error = dnsSdResponderFormatPtrRecord(interface, response,
476  service, ttl);
477  //Any error to report?
478  if(error)
479  return error;
480 
481  //Update the number of shared resource records
482  response->sharedRecordCount++;
483  }
484  }
485  else if(!mdnsCompareName(query->dnsHeader, query->length, offset,
486  service->instanceName, service->serviceName, ".local", 0))
487  {
488  //SRV query?
489  if(qtype == DNS_RR_TYPE_SRV || qtype == DNS_RR_TYPE_ANY)
490  {
491  //Format SRV resource record
492  error = dnsSdResponderFormatSrvRecord(interface, response,
493  service, cacheFlush, ttl);
494  //Any error to report?
495  if(error)
496  return error;
497  }
498 
499  //TXT query?
500  if(qtype == DNS_RR_TYPE_TXT || qtype == DNS_RR_TYPE_ANY)
501  {
502  //Format TXT resource record
503  error = dnsSdResponderFormatTxtRecord(interface, response,
504  service, cacheFlush, ttl);
505  //Any error to report?
506  if(error)
507  return error;
508  }
509 
510  //NSEC query?
511  if(qtype != DNS_RR_TYPE_SRV && qtype != DNS_RR_TYPE_TXT)
512  {
513  //Format NSEC resource record
514  error = dnsSdResponderFormatNsecRecord(interface, response,
515  service, cacheFlush, ttl);
516  //Any error to report?
517  if(error)
518  return error;
519  }
520  }
521  }
522  }
523  }
524 
525  //Successful processing
526  return NO_ERROR;
527 }
528 
529 
530 /**
531  * @brief Parse the Authority Section
532  * @param[in] interface Underlying network interface
533  * @param[in] query Incoming mDNS query message
534  * @param[in] offset Offset to first byte of the resource record
535  **/
536 
538  const MdnsMessage *query, size_t offset)
539 {
540  uint_t i;
541  uint_t j;
542  int_t res;
543  DnsSdResponderContext *context;
544  DnsSdResponderService *service;
545  DnsResourceRecord *record;
546 
547  //Point to the DNS-SD responder context
548  context = interface->dnsSdResponderContext;
549  //Make sure the DNS-SD responder has been properly instantiated
550  if(context == NULL)
551  return;
552 
553  //Loop through the list of registered services
554  for(i = 0; i < context->numServices; i++)
555  {
556  //Point to the current entry
557  service = &context->services[i];
558 
559  //Valid service?
560  if(service->instanceName[0] != '\0' &&
561  service->serviceName[0] != '\0')
562  {
563  //Get the first tiebreaker record in lexicographical order
564  record = dnsSdResponderGetNextTiebreakerRecord(service, query, offset,
565  NULL);
566 
567  //When a host is probing for a set of records with the same name, or a
568  //message is received containing multiple tiebreaker records answering
569  //a given probe question in the Question Section, the host's records
570  //and the tiebreaker records from the message are each sorted into order
571  for(j = 1; ; j++)
572  {
573  //The records are compared pairwise
574  if(record == NULL && j >= 3)
575  {
576  //If both lists run out of records at the same time without any
577  //difference being found, then this indicates that two devices
578  //are advertising identical sets of records, as is sometimes done
579  //for fault tolerance, and there is, in fact, no conflict
580  break;
581  }
582  else if(record != NULL && j >= 3)
583  {
584  //If either list of records runs out of records before any
585  //difference is found, then the list with records remaining is
586  //deemed to have won the tiebreak
587  service->tieBreakLost = TRUE;
588  break;
589  }
590  else if(record == NULL && j < 3)
591  {
592  //The host has won the tiebreak
593  break;
594  }
595  else
596  {
597  //The two records are compared and the lexicographically later data
598  //wins
599  if(j == 1)
600  {
601  res = dnsSdResponderCompareTxtRecord(service, query, record);
602  }
603  else
604  {
605  res = dnsSdResponderCompareSrvRecord(interface, service, query, record);
606  }
607 
608  //Check comparison result
609  if(res > 0)
610  {
611  //If the host finds that its own data is lexicographically earlier,
612  //then it defers to the winning host by waiting one second, and
613  //then begins probing for this record again
614  service->tieBreakLost = TRUE;
615  break;
616  }
617  else if(res < 0)
618  {
619  //If the host finds that its own data is lexicographically later,
620  //it simply ignores the other host's probe
621  break;
622  }
623  else
624  {
625  //When comparing the records, if the first records match perfectly,
626  //then the second records are compared, and so on
627  }
628  }
629 
630  //Get the next tiebreaker record in lexicographical order
631  record = dnsSdResponderGetNextTiebreakerRecord(service, query, offset,
632  record);
633  }
634  }
635  }
636 }
637 
638 
639 /**
640  * @brief Parse a resource record from the Answer Section
641  * @param[in] interface Underlying network interface
642  * @param[in] response Incoming mDNS response message
643  * @param[in] offset Offset to first byte of the resource record to be checked
644  * @param[in] record Pointer to the resource record
645  **/
646 
648  const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
649 {
650  uint_t i;
651  uint16_t rclass;
652  DnsSdResponderContext *context;
653  DnsSdResponderService *service;
654 
655  //Point to the DNS-SD responder context
656  context = interface->dnsSdResponderContext;
657  //Make sure the DNS-SD responder has been properly instantiated
658  if(context == NULL)
659  return;
660 
661  //Loop through the list of registered services
662  for(i = 0; i < context->numServices; i++)
663  {
664  //Point to the current entry
665  service = &context->services[i];
666 
667  //Valid service?
668  if(service->instanceName[0] != '\0' &&
669  service->serviceName[0] != '\0')
670  {
671  //Check for conflicts
672  if(!mdnsCompareName(response->dnsHeader, response->length, offset,
673  service->instanceName, service->serviceName, ".local", 0))
674  {
675  //Convert the class to host byte order
676  rclass = ntohs(record->rclass);
677  //Discard Cache Flush flag
679 
680  //Check the class of the resource record
681  if(rclass == DNS_RR_CLASS_IN)
682  {
683  //A conflict occurs when a mDNS responder has a unique record
684  //for which it is currently authoritative, and it receives a
685  //mDNS response message containing a record with the same name,
686  //rrtype and rrclass, but inconsistent rdata
687  if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
688  {
689  //Inconsistent rdata?
690  if(dnsSdResponderCompareSrvRecord(interface, service,
691  response, record) != 0)
692  {
693  //The service instance name is already in use by some
694  //other host
695  service->conflict = TRUE;
696  }
697  }
698  else if(ntohs(record->rtype) == DNS_RR_TYPE_TXT)
699  {
700  //Inconsistent rdata?
701  if(dnsSdResponderCompareTxtRecord(service, response,
702  record) != 0)
703  {
704  //The service instance name is already in use by some
705  //other host
706  service->conflict = TRUE;
707  }
708  }
709  else
710  {
711  //Just for sanity
712  }
713  }
714  }
715  }
716  }
717 }
718 
719 
720 /**
721  * @brief Additional record generation
722  * @param[in] interface Underlying network interface
723  * @param[in,out] response mDNS response message
724  * @param[in] legacyUnicast This flag is set for legacy unicast responses
725  **/
726 
728  MdnsMessage *response, bool_t legacyUnicast)
729 {
730 #if (DNS_SD_ADDITIONAL_RECORDS_SUPPORT == ENABLED)
731  uint_t i;
732  uint_t j;
733  size_t n;
734  size_t offset;
735  uint_t ancount;
736  uint16_t rclass;
737  uint32_t ttl;
738  bool_t cacheFlush;
739  DnsSdResponderContext *context;
740  DnsSdResponderService *service;
741  DnsResourceRecord *record;
742 
743  //Point to the DNS-SD responder context
744  context = interface->dnsSdResponderContext;
745  //Make sure the DNS-SD responder has been properly instantiated
746  if(context == NULL)
747  return;
748 
749  //mDNS responses must not contain any questions in the Question Section
750  if(response->dnsHeader->qdcount != 0)
751  return;
752 
753  //Get the TTL resource record
754  ttl = context->ttl;
755 
756  //Check whether the querier originating the query is a simple resolver
757  if(legacyUnicast)
758  {
759  //The resource record TTL given in a legacy unicast response should
760  //not be greater than ten seconds, even if the true TTL of the mDNS
761  //resource record is higher
763 
764  //The cache-flush bit must not be set in legacy unicast responses
765  cacheFlush = FALSE;
766  }
767  else
768  {
769  //The cache-bit should be set for unique resource records
770  cacheFlush = TRUE;
771  }
772 
773  //Point to the first resource record
774  offset = sizeof(DnsHeader);
775 
776  //Save the number of resource records in the Answer Section
777  ancount = response->dnsHeader->ancount;
778 
779  //Parse the Answer Section
780  for(i = 0; i < ancount; i++)
781  {
782  //Parse resource record name
783  n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
784  //Invalid name?
785  if(!n)
786  break;
787 
788  //Point to the associated resource record
789  record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
790  //Point to the resource data
791  n += sizeof(DnsResourceRecord);
792 
793  //Make sure the resource record is valid
794  if(n > response->length)
795  break;
796  if((n + ntohs(record->rdlength)) > response->length)
797  break;
798 
799  //Convert the record class to host byte order
800  rclass = ntohs(record->rclass);
801  //Discard the cache-flush bit
803 
804  //Loop through the list of registered services
805  for(j = 0; j < context->numServices; j++)
806  {
807  //Point to the current entry
808  service = &context->services[j];
809 
810  //Valid service?
811  if(service->instanceName[0] != '\0' &&
812  service->serviceName[0] != '\0')
813  {
814  //Check the class of the resource record
815  if(rclass == DNS_RR_CLASS_IN)
816  {
817  //PTR record?
818  if(ntohs(record->rtype) == DNS_RR_TYPE_PTR)
819  {
820  //Compare service name
821  if(!mdnsCompareName(response->dnsHeader, response->length,
822  offset, "", service->serviceName, ".local", 0))
823  {
824  //Format SRV resource record
825  dnsSdResponderFormatSrvRecord(interface, response, service,
826  cacheFlush, ttl);
827 
828  //Format TXT resource record
829  dnsSdResponderFormatTxtRecord(interface, response, service,
830  cacheFlush, ttl);
831  }
832  }
833  //SRV record?
834  else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
835  {
836  //Compare service name
837  if(!mdnsCompareName(response->dnsHeader, response->length,
838  offset, service->instanceName, service->serviceName,
839  ".local", 0))
840  {
841  //Format TXT resource record
842  dnsSdResponderFormatTxtRecord(interface, response, service,
843  cacheFlush, ttl);
844  }
845  }
846  }
847  }
848  }
849 
850  //Point to the next resource record
851  offset = n + ntohs(record->rdlength);
852  }
853 
854  //Number of resource records in the Additional Section
855  response->dnsHeader->arcount += response->dnsHeader->ancount - ancount;
856  //Number of resource records in the Answer Section
857  response->dnsHeader->ancount = ancount;
858 #endif
859 }
860 
861 
862 /**
863  * @brief Format PTR resource record (in response to a meta-query)
864  * @param[in] interface Underlying network interface
865  * @param[in,out] message Pointer to the mDNS message
866  * @param[in] service Pointer to a DNS-SD service
867  * @param[in] ttl Resource record TTL (cache lifetime)
868  * @return Error code
869  **/
870 
872  MdnsMessage *message, const DnsSdResponderService *service, uint32_t ttl)
873 {
874  size_t n;
875  size_t offset;
876  bool_t duplicate;
877  DnsResourceRecord *record;
878 
879  //Check whether the resource record is already present in the Answer
880  //Section of the message
881  duplicate = mdnsCheckDuplicateRecord(message, "", "_services._dns-sd._udp",
882  ".local", DNS_RR_TYPE_PTR, NULL, 0);
883 
884  //The duplicates should be suppressed and the resource record should
885  //appear only once in the list
886  if(!duplicate)
887  {
888  //Set the position to the end of the buffer
889  offset = message->length;
890 
891  //The first pass calculates the length of the DNS encoded service name
892  n = mdnsEncodeName("", "_services._dns-sd._udp", ".local", NULL);
893 
894  //Check the length of the resulting mDNS message
895  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
896  return ERROR_MESSAGE_TOO_LONG;
897 
898  //The second pass encodes the service name using the DNS name notation
899  offset += mdnsEncodeName("", "_services._dns-sd._udp", ".local",
900  (uint8_t *) message->dnsHeader + offset);
901 
902  //Consider the length of the resource record itself
903  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
904  return ERROR_MESSAGE_TOO_LONG;
905 
906  //Point to the corresponding resource record
907  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
908 
909  //Fill in resource record
910  record->rtype = HTONS(DNS_RR_TYPE_PTR);
911  record->rclass = HTONS(DNS_RR_CLASS_IN);
912  record->ttl = htonl(ttl);
913 
914  //Advance write index
915  offset += sizeof(DnsResourceRecord);
916 
917  //The first pass calculates the length of the DNS encoded service name
918  n = mdnsEncodeName("", service->serviceName, ".local", NULL);
919 
920  //Check the length of the resulting mDNS message
921  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
922  return ERROR_MESSAGE_TOO_LONG;
923 
924  //The second pass encodes the service name using DNS notation
925  n = mdnsEncodeName("", service->serviceName, ".local", record->rdata);
926 
927  //Convert length field to network byte order
928  record->rdlength = htons(n);
929 
930  //Number of resource records in the answer section
931  message->dnsHeader->ancount++;
932  //Update the length of the DNS message
933  message->length = offset + n;
934  }
935 
936  //Successful processing
937  return NO_ERROR;
938 }
939 
940 
941 /**
942  * @brief Format PTR resource record
943  * @param[in] interface Underlying network interface
944  * @param[in,out] message Pointer to the mDNS message
945  * @param[in] service Pointer to a DNS-SD service
946  * @param[in] ttl Resource record TTL (cache lifetime)
947  * @return Error code
948  **/
949 
951  MdnsMessage *message, const DnsSdResponderService *service, uint32_t ttl)
952 {
953  size_t n;
954  size_t offset;
955  bool_t duplicate;
956  uint8_t *p;
957  DnsResourceRecord *record;
958 
959  //Set the position to the end of the buffer
960  p = (uint8_t *) message->dnsHeader + message->length;
961  offset = message->length;
962 
963  //The first pass calculates the length of the DNS encoded instance name
964  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
965  NULL);
966 
967  //Sanity check
968  if((message->length + n) > MDNS_MESSAGE_MAX_SIZE)
969  return ERROR_MESSAGE_TOO_LONG;
970 
971  //The second pass encodes the instance name using DNS notation
972  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local", p);
973 
974  //Check whether the resource record is already present in the Answer
975  //Section of the message
976  duplicate = mdnsCheckDuplicateRecord(message, "", service->serviceName,
977  ".local", DNS_RR_TYPE_PTR, p, n);
978 
979  //The duplicates should be suppressed and the resource record should
980  //appear only once in the list
981  if(!duplicate)
982  {
983  //The first pass calculates the length of the DNS encoded service name
984  n = mdnsEncodeName("", service->serviceName, ".local", NULL);
985 
986  //Check the length of the resulting mDNS message
987  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
988  return ERROR_MESSAGE_TOO_LONG;
989 
990  //The second pass encodes the service name using the DNS name notation
991  offset += mdnsEncodeName("", service->serviceName, ".local", p);
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 instance name
1009  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1010  NULL);
1011 
1012  //Check the length of the resulting mDNS message
1013  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1014  return ERROR_MESSAGE_TOO_LONG;
1015 
1016  //The second pass encodes the instance name using DNS notation
1017  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1018  record->rdata);
1019 
1020  //Convert length field to network byte order
1021  record->rdlength = htons(n);
1022 
1023  //Number of resource records in the answer section
1024  message->dnsHeader->ancount++;
1025  //Update the length of the DNS message
1026  message->length = offset + n;
1027  }
1028 
1029  //Successful processing
1030  return NO_ERROR;
1031 }
1032 
1033 
1034 /**
1035  * @brief Format SRV resource record
1036  * @param[in] interface Underlying network interface
1037  * @param[in,out] message Pointer to the mDNS message
1038  * @param[in] service Pointer to a DNS-SD service
1039  * @param[in] cacheFlush Cache-flush bit
1040  * @param[in] ttl Resource record TTL (cache lifetime)
1041  * @return Error code
1042  **/
1043 
1045  MdnsMessage *message, const DnsSdResponderService *service,
1046  bool_t cacheFlush, uint32_t ttl)
1047 {
1048  size_t n;
1049  size_t offset;
1050  bool_t duplicate;
1051  MdnsResponderContext *mdnsResponderContext;
1052  DnsSrvResourceRecord *record;
1053 
1054  //Point to the mDNS responder context
1055  mdnsResponderContext = interface->mdnsResponderContext;
1056 
1057  //Check whether the resource record is already present in the Answer
1058  //Section of the message
1059  duplicate = mdnsCheckDuplicateRecord(message, service->instanceName,
1060  service->serviceName, ".local", DNS_RR_TYPE_SRV, NULL, 0);
1061 
1062  //The duplicates should be suppressed and the resource record should
1063  //appear only once in the list
1064  if(!duplicate)
1065  {
1066  //Set the position to the end of the buffer
1067  offset = message->length;
1068 
1069  //The first pass calculates the length of the DNS encoded instance name
1070  n = mdnsEncodeName(service->instanceName, service->serviceName,
1071  ".local", NULL);
1072 
1073  //Check the length of the resulting mDNS message
1074  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1075  return ERROR_MESSAGE_TOO_LONG;
1076 
1077  //The second pass encodes the instance name using DNS notation
1078  offset += mdnsEncodeName(service->instanceName, service->serviceName,
1079  ".local", (uint8_t *) message->dnsHeader + offset);
1080 
1081  //Consider the length of the resource record itself
1082  if((offset + sizeof(DnsSrvResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1083  return ERROR_MESSAGE_TOO_LONG;
1084 
1085  //Point to the corresponding resource record
1086  record = (DnsSrvResourceRecord *) DNS_GET_RESOURCE_RECORD(message->dnsHeader,
1087  offset);
1088 
1089  //Fill in resource record
1090  record->rtype = HTONS(DNS_RR_TYPE_SRV);
1091  record->rclass = HTONS(DNS_RR_CLASS_IN);
1092  record->ttl = htonl(ttl);
1093  record->priority = htons(service->priority);
1094  record->weight = htons(service->weight);
1095  record->port = htons(service->port);
1096 
1097  //Check whether the cache-flush bit should be set
1098  if(cacheFlush)
1099  {
1100  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1101  }
1102 
1103  //Advance write index
1104  offset += sizeof(DnsSrvResourceRecord);
1105 
1106  //The first pass calculates the length of the DNS encoded target name
1107  n = mdnsEncodeName("", mdnsResponderContext->hostname, ".local", NULL);
1108 
1109  //Check the length of the resulting mDNS message
1110  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1111  return ERROR_MESSAGE_TOO_LONG;
1112 
1113  //The second pass encodes the target name using DNS notation
1114  n = mdnsEncodeName("", mdnsResponderContext->hostname, ".local",
1115  record->target);
1116 
1117  //Calculate data length
1118  record->rdlength = htons(sizeof(DnsSrvResourceRecord) -
1119  sizeof(DnsResourceRecord) + n);
1120 
1121  //Number of resource records in the answer section
1122  message->dnsHeader->ancount++;
1123  //Update the length of the DNS message
1124  message->length = offset + n;
1125  }
1126 
1127  //Successful processing
1128  return NO_ERROR;
1129 }
1130 
1131 
1132 /**
1133  * @brief Format TXT resource record
1134  * @param[in] interface Underlying network interface
1135  * @param[in,out] message Pointer to the mDNS message
1136  * @param[in] service Pointer to a DNS-SD service
1137  * @param[in] cacheFlush Cache-flush bit
1138  * @param[in] ttl Resource record TTL (cache lifetime)
1139  * @return Error code
1140  **/
1141 
1143  MdnsMessage *message, const DnsSdResponderService *service,
1144  bool_t cacheFlush, uint32_t ttl)
1145 {
1146  size_t n;
1147  size_t offset;
1148  bool_t duplicate;
1149  DnsResourceRecord *record;
1150 
1151  //Check whether the resource record is already present in the Answer
1152  //Section of the message
1153  duplicate = mdnsCheckDuplicateRecord(message, service->instanceName,
1154  service->serviceName, ".local", DNS_RR_TYPE_TXT, NULL, 0);
1155 
1156  //The duplicates should be suppressed and the resource record should
1157  //appear only once in the list
1158  if(!duplicate)
1159  {
1160  //Set the position to the end of the buffer
1161  offset = message->length;
1162 
1163  //The first pass calculates the length of the DNS encoded instance name
1164  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1165  NULL);
1166 
1167  //Check the length of the resulting mDNS message
1168  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1169  return ERROR_MESSAGE_TOO_LONG;
1170 
1171  //The second pass encodes the instance name using DNS notation
1172  offset += mdnsEncodeName(service->instanceName, service->serviceName,
1173  ".local", (uint8_t *) message->dnsHeader + offset);
1174 
1175  //Consider the length of the resource record itself
1176  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1177  return ERROR_MESSAGE_TOO_LONG;
1178 
1179  //Point to the corresponding resource record
1180  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1181 
1182  //Fill in resource record
1183  record->rtype = HTONS(DNS_RR_TYPE_TXT);
1184  record->rclass = HTONS(DNS_RR_CLASS_IN);
1185  record->ttl = htonl(ttl);
1186  record->rdlength = htons(service->metadataLen);
1187 
1188  //Check whether the cache-flush bit should be set
1189  if(cacheFlush)
1190  {
1191  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1192  }
1193 
1194  //Advance write index
1195  offset += sizeof(DnsResourceRecord);
1196 
1197  //Check the length of the resulting mDNS message
1198  if((offset + service->metadataLen) > MDNS_MESSAGE_MAX_SIZE)
1199  return ERROR_MESSAGE_TOO_LONG;
1200 
1201  //Copy metadata
1202  osMemcpy(record->rdata, service->metadata, service->metadataLen);
1203 
1204  //Update the length of the DNS message
1205  message->length = offset + service->metadataLen;
1206  //Number of resource records in the answer section
1207  message->dnsHeader->ancount++;
1208  }
1209 
1210  //Successful processing
1211  return NO_ERROR;
1212 }
1213 
1214 
1215 /**
1216  * @brief Format NSEC resource record
1217  * @param[in] interface Underlying network interface
1218  * @param[in,out] message Pointer to the mDNS message
1219  * @param[in] service Pointer to a DNS-SD service
1220  * @param[in] cacheFlush Cache-flush bit
1221  * @param[in] ttl Resource record TTL (cache lifetime)
1222  * @return Error code
1223  **/
1224 
1226  MdnsMessage *message, const DnsSdResponderService *service,
1227  bool_t cacheFlush, uint32_t ttl)
1228 {
1229  size_t n;
1230  size_t offset;
1231  bool_t duplicate;
1232  size_t bitmapLen;
1233  uint8_t bitmap[8];
1234  DnsResourceRecord *record;
1235 
1236  //Check whether the resource record is already present in the Answer
1237  //Section of the message
1238  duplicate = mdnsCheckDuplicateRecord(message, service->instanceName,
1239  service->serviceName, ".local", DNS_RR_TYPE_NSEC, NULL, 0);
1240 
1241  //The duplicates should be suppressed and the resource record should
1242  //appear only once in the list
1243  if(!duplicate)
1244  {
1245  //The bitmap identifies the resource record types that exist
1246  osMemset(bitmap, 0, sizeof(bitmap));
1247 
1248  //TXT resource record is supported
1250  //SRV resource record is supported
1252 
1253  //Compute the length of the bitmap
1254  for(bitmapLen = sizeof(bitmap); bitmapLen > 0; bitmapLen--)
1255  {
1256  //Trailing zero octets in the bitmap must be omitted
1257  if(bitmap[bitmapLen - 1] != 0)
1258  {
1259  break;
1260  }
1261  }
1262 
1263  //Set the position to the end of the buffer
1264  offset = message->length;
1265 
1266  //The first pass calculates the length of the DNS encoded instance name
1267  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1268  NULL);
1269 
1270  //Check the length of the resulting mDNS message
1271  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1272  return ERROR_MESSAGE_TOO_LONG;
1273 
1274  //The second pass encodes the instance name using the DNS name notation
1275  offset += mdnsEncodeName(service->instanceName, service->serviceName,
1276  ".local", (uint8_t *) message->dnsHeader + offset);
1277 
1278  //Consider the length of the resource record itself
1279  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1280  return ERROR_MESSAGE_TOO_LONG;
1281 
1282  //Point to the corresponding resource record
1283  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1284 
1285  //Fill in resource record
1286  record->rtype = HTONS(DNS_RR_TYPE_NSEC);
1287  record->rclass = HTONS(DNS_RR_CLASS_IN);
1288  record->ttl = htonl(ttl);
1289 
1290  //Check whether the cache-flush bit should be set
1291  if(cacheFlush)
1292  {
1293  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1294  }
1295 
1296  //Advance write index
1297  offset += sizeof(DnsResourceRecord);
1298 
1299  //Check the length of the resulting mDNS message
1300  if((offset + n + 2) > MDNS_MESSAGE_MAX_SIZE)
1301  return ERROR_MESSAGE_TOO_LONG;
1302 
1303  //The Next Domain Name field contains the record's own name
1304  mdnsEncodeName(service->instanceName, service->serviceName,
1305  ".local", record->rdata);
1306 
1307  //DNS NSEC record is limited to Window Block number zero
1308  record->rdata[n++] = 0;
1309  //The Bitmap Length is a value in the range 1-32
1310  record->rdata[n++] = bitmapLen;
1311 
1312  //The Bitmap data identifies the resource record types that exist
1313  osMemcpy(record->rdata + n, bitmap, bitmapLen);
1314 
1315  //Convert length field to network byte order
1316  record->rdlength = htons(n + bitmapLen);
1317 
1318  //Number of resource records in the answer section
1319  message->dnsHeader->ancount++;
1320  //Update the length of the DNS message
1321  message->length = offset + n + bitmapLen;
1322  }
1323 
1324  //Successful processing
1325  return NO_ERROR;
1326 }
1327 
1328 
1329 /**
1330  * @brief Sort the tiebreaker records in lexicographical order
1331  * @param[in] service Pointer to a DNS-SD service
1332  * @param[in] query Incoming mDNS query message
1333  * @param[in] offset Offset to first byte of the Authority Section
1334  * @param[in] record Pointer to the current record
1335  * @return Pointer to the next record, if any
1336  **/
1337 
1339  DnsSdResponderService *service, const MdnsMessage *query, size_t offset,
1340  DnsResourceRecord *record)
1341 {
1342  uint_t i;
1343  size_t n;
1344  int_t res;
1345  DnsResourceRecord *curRecord;
1346  DnsResourceRecord *nextRecord;
1347 
1348  //Initialize record pointer
1349  nextRecord = NULL;
1350 
1351  //Parse Authority Section
1352  for(i = 0; i < ntohs(query->dnsHeader->nscount); i++)
1353  {
1354  //Parse resource record name
1355  n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
1356  //Invalid name?
1357  if(!n)
1358  break;
1359 
1360  //Point to the associated resource record
1361  curRecord = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
1362  //Point to the resource data
1363  n += sizeof(DnsResourceRecord);
1364 
1365  //Make sure the resource record is valid
1366  if(n > query->length)
1367  break;
1368  if((n + ntohs(curRecord->rdlength)) > query->length)
1369  break;
1370 
1371  //Matching host name?
1372  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
1373  service->instanceName, service->serviceName, ".local", 0))
1374  {
1375  //Perform lexicographical comparison
1376  if(record != NULL)
1377  {
1378  res = mdnsCompareRecord(query, curRecord, query, record);
1379  }
1380  else
1381  {
1382  res = 1;
1383  }
1384 
1385  //Check whether the record is lexicographically later
1386  if(res > 0)
1387  {
1388  if(nextRecord == NULL)
1389  {
1390  nextRecord = curRecord;
1391  }
1392  else if(mdnsCompareRecord(query, curRecord, query, nextRecord) < 0)
1393  {
1394  nextRecord = curRecord;
1395  }
1396  }
1397  }
1398 
1399  //Point to the next resource record
1400  offset = n + ntohs(curRecord->rdlength);
1401  }
1402 
1403  //Return the pointer to the next record
1404  return nextRecord;
1405 }
1406 
1407 
1408 /**
1409  * @brief Compare SRV resource records
1410  * @param[in] interface Underlying network interface
1411  * @param[in] service Pointer to a DNS-SD service
1412  * @param[in] message Pointer to mDNS message
1413  * @param[in] record Pointer the resource record
1414  * @return The function returns 0 if the resource record match the SRV resource
1415  * record of the host, -1 if the resource record lexicographically precedes
1416  * it, or 1 if the resource record lexicographically precedes it
1417  **/
1418 
1420  DnsSdResponderService *service, const MdnsMessage *message,
1421  const DnsResourceRecord *record)
1422 {
1423  int_t res;
1424  size_t offset;
1425  uint16_t value;
1426  MdnsResponderContext *mdnsResponderContext;
1427  DnsSrvResourceRecord *srvRecord;
1428 
1429  //Point to the mDNS responder context
1430  mdnsResponderContext = interface->mdnsResponderContext;
1431 
1432  //Convert the record class to host byte order
1433  value = ntohs(record->rclass);
1434  //Discard cache-flush bit
1436 
1437  //The determination of lexicographically later record is performed by
1438  //first comparing the record class (excluding the cache-flush bit)
1439  if(value < DNS_RR_CLASS_IN)
1440  {
1441  return -1;
1442  }
1443  else if(value > DNS_RR_CLASS_IN)
1444  {
1445  return 1;
1446  }
1447  else
1448  {
1449  }
1450 
1451  //Convert the record type to host byte order
1452  value = ntohs(record->rtype);
1453 
1454  //Then compare the record type
1455  if(value < DNS_RR_TYPE_SRV)
1456  {
1457  return -1;
1458  }
1459  else if(value > DNS_RR_TYPE_SRV)
1460  {
1461  return 1;
1462  }
1463  else
1464  {
1465  }
1466 
1467  //If the rrtype and rrclass both match, then the rdata is compared
1468  srvRecord = (DnsSrvResourceRecord *) record;
1469  //Convert the Priority field to host byte order
1470  value = ntohs(srvRecord->priority);
1471 
1472  //Compare Priority fields
1473  if(value < service->priority)
1474  {
1475  return -1;
1476  }
1477  else if(value > service->priority)
1478  {
1479  return 1;
1480  }
1481  else
1482  {
1483  }
1484 
1485  //Convert the Weight field to host byte order
1486  value = ntohs(srvRecord->weight);
1487 
1488  //Compare Weight fields
1489  if(value < service->weight)
1490  {
1491  return -1;
1492  }
1493  else if(value > service->weight)
1494  {
1495  return 1;
1496  }
1497  else
1498  {
1499  }
1500 
1501  //Convert the Port field to host byte order
1502  value = ntohs(srvRecord->port);
1503 
1504  //Compare Port fields
1505  if(value < service->port)
1506  {
1507  return -1;
1508  }
1509  else if(value > service->port)
1510  {
1511  return 1;
1512  }
1513  else
1514  {
1515  }
1516 
1517  //Compute the offset of the first byte of the Target field
1518  offset = srvRecord->target - (uint8_t *) message->dnsHeader;
1519 
1520  //Compare Target fields
1521  res = mdnsCompareName(message->dnsHeader, message->length, offset,
1522  "", mdnsResponderContext->hostname, ".local", 0);
1523 
1524  //Return comparison result
1525  return res;
1526 }
1527 
1528 
1529 /**
1530  * @brief Compare TXT resource records
1531  * @param[in] service Pointer to a DNS-SD service
1532  * @param[in] message Pointer to mDNS message
1533  * @param[in] record Pointer the resource record
1534  * @return The function returns 0 if the resource record match the TXT resource
1535  * record of the host, -1 if the resource record lexicographically precedes
1536  * it, or 1 if the resource record lexicographically precedes it
1537  **/
1538 
1540  const MdnsMessage *message, const DnsResourceRecord *record)
1541 {
1542  int_t res;
1543  size_t n;
1544  uint16_t value;
1545 
1546  //Convert the record class to host byte order
1547  value = ntohs(record->rclass);
1548  //Discard cache-flush bit
1550 
1551  //The determination of lexicographically later record is performed by
1552  //first comparing the record class (excluding the cache-flush bit)
1553  if(value < DNS_RR_CLASS_IN)
1554  {
1555  return -1;
1556  }
1557  else if(value > DNS_RR_CLASS_IN)
1558  {
1559  return 1;
1560  }
1561  else
1562  {
1563  }
1564 
1565  //Convert the record type to host byte order
1566  value = ntohs(record->rtype);
1567 
1568  //Then compare the record type
1569  if(value < DNS_RR_TYPE_TXT)
1570  {
1571  return -1;
1572  }
1573  else if(value > DNS_RR_TYPE_TXT)
1574  {
1575  return 1;
1576  }
1577  else
1578  {
1579  }
1580 
1581  //Retrieve the length of the rdata fields
1582  n = htons(record->rdlength);
1583 
1584  //The bytes of the raw uncompressed rdata are compared in turn, interpreting
1585  //the bytes as eight-bit unsigned values, until a byte is found whose value
1586  //is greater than that of its counterpart (in which case, the rdata whose
1587  //byte has the greater value is deemed lexicographically later) or one of the
1588  //resource records runs out of rdata (in which case, the resource record which
1589  //still has remaining data first is deemed lexicographically later)
1590  if(n < service->metadataLen)
1591  {
1592  //Raw comparison of the binary content of the rdata
1593  res = osMemcmp(record->rdata, service->metadata, n);
1594 
1595  //Check comparison result
1596  if(!res)
1597  {
1598  //The first resource records runs out of rdata
1599  res = -1;
1600  }
1601  }
1602  else if(n > service->metadataLen)
1603  {
1604  //Raw comparison of the binary content of the rdata
1605  res = osMemcmp(record->rdata, service->metadata, service->metadataLen);
1606 
1607  //Check comparison result
1608  if(!res)
1609  {
1610  //The second resource records runs out of rdata
1611  res = 1;
1612  }
1613  }
1614  else
1615  {
1616  //Raw comparison of the binary content of the rdata
1617  res = osMemcmp(record->rdata, service->metadata, n);
1618  }
1619 
1620  //Return comparison result
1621  return res;
1622 }
1623 
1624 #endif
#define MdnsResponderContext
#define htons(value)
Definition: cpu_endian.h:413
error_t dnsSdResponderSendGoodbye(DnsSdResponderService *service)
Send goodbye packet.
int bool_t
Definition: compiler_port.h:53
@ DNS_RR_CLASS_ANY
Any class.
Definition: dns_common.h:127
DnsSrvResourceRecord
Definition: dns_common.h:269
signed int int_t
Definition: compiler_port.h:49
#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:648
uint16_t weight
Definition: dns_common.h:266
uint_t sharedRecordCount
Definition: mdns_common.h:87
uint8_t p
Definition: ndp.h:300
#define DNS_SET_NSEC_BITMAP(bitmap, type)
Definition: dns_common.h:66
uint8_t message[]
Definition: chap.h:154
void dnsSdResponderParseAnRecord(NetInterface *interface, const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
error_t dnsSdResponderFormatServiceEnumPtrRecord(NetInterface *interface, MdnsMessage *message, const DnsSdResponderService *service, uint32_t ttl)
Format PTR resource record (in response to a meta-query)
#define TRUE
Definition: os_port.h:50
error_t dnsSdResponderFormatNsecRecord(NetInterface *interface, MdnsMessage *message, const DnsSdResponderService *service, bool_t cacheFlush, uint32_t ttl)
Format NSEC resource record.
#define DNS_SD_DEFAULT_RR_TTL
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:921
error_t dnsSdResponderParseQuestion(NetInterface *interface, const MdnsMessage *query, size_t offset, const DnsQuestion *question, MdnsMessage *response)
Parse a question.
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
error_t dnsSdResponderSendAnnouncement(DnsSdResponderService *service)
Send announcement packet.
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
DnsHeader * dnsHeader
Definition: mdns_common.h:84
uint16_t rclass
Definition: dns_common.h:220
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:124
DnsHeader
Definition: dns_common.h:199
#define osStrlen(s)
Definition: os_port.h:165
const uint8_t res[]
MdnsState
mDNS responder states
#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
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
error_t dnsSdResponderFormatSrvRecord(NetInterface *interface, MdnsMessage *message, const DnsSdResponderService *service, bool_t cacheFlush, uint32_t ttl)
Format SRV resource record.
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
void dnsSdResponderChangeInstanceName(DnsSdResponderService *service)
Programmatically change the service instance name.
DNS-SD responder (DNS-Based Service Discovery)
@ MDNS_STATE_PROBING
size_t length
Definition: mdns_common.h:81
uint16_t qclass
Definition: dns_common.h:209
error_t dnsSdResponderFormatPtrRecord(NetInterface *interface, MdnsMessage *message, const DnsSdResponderService *service, uint32_t ttl)
Format PTR resource record.
#define NetInterface
Definition: net.h:36
#define DnsSdResponderContext
int_t dnsSdResponderCompareTxtRecord(DnsSdResponderService *service, const MdnsMessage *message, const DnsResourceRecord *record)
Compare TXT resource records.
@ 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
#define DnsSdResponderService
#define osIsdigit(c)
Definition: os_port.h:285
#define DNS_SD_MAX_INSTANCE_NAME_LEN
@ ERROR_MESSAGE_TOO_LONG
Definition: error.h:136
#define MIN(a, b)
Definition: os_port.h:63
@ MDNS_STATE_WAITING
@ MDNS_STATE_INIT
error_t dnsSdResponderSendProbe(DnsSdResponderService *service)
Send probe packet.
uint32_t systime_t
System time.
uint16_t port
Definition: dns_common.h:267
int_t mdnsCompareRecord(const MdnsMessage *message1, const DnsResourceRecord *record1, const MdnsMessage *message2, const DnsResourceRecord *record2)
Compare resource records.
Definition: mdns_common.c:799
#define ntohs(value)
Definition: cpu_endian.h:421
void dnsSdResponderParseNsRecords(NetInterface *interface, const MdnsMessage *query, size_t offset)
Parse the Authority Section.
mDNS message
Definition: mdns_common.h:78
char char_t
Definition: compiler_port.h:48
#define osStrcat(s1, s2)
Definition: os_port.h:219
void dnsSdResponderChangeState(DnsSdResponderService *service, MdnsState newState, systime_t delay)
Update FSM state.
void dnsSdResponderGenerateAdditionalRecords(NetInterface *interface, MdnsMessage *response, bool_t legacyUnicast)
Additional record generation.
int_t dnsSdResponderCompareSrvRecord(NetInterface *interface, DnsSdResponderService *service, const MdnsMessage *message, const DnsResourceRecord *record)
Compare SRV resource records.
Helper functions for DNS-SD responder.
void mdnsDeleteMessage(MdnsMessage *message)
release a mDNS message
Definition: mdns_common.c:434
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
DnsQuestion
Definition: dns_common.h:210
#define MDNS_MESSAGE_MAX_SIZE
Definition: mdns_common.h:40
uint8_t value[]
Definition: tcp.h:369
uint8_t s
Definition: igmp_common.h:234
DnsResourceRecord * dnsSdResponderGetNextTiebreakerRecord(DnsSdResponderService *service, const MdnsMessage *query, size_t offset, DnsResourceRecord *record)
Sort the tiebreaker records in lexicographical order.
@ DNS_RR_TYPE_SRV
Server selection.
Definition: dns_common.h:149
error_t dnsSdResponderFormatTxtRecord(NetInterface *interface, MdnsMessage *message, const DnsSdResponderService *service, bool_t cacheFlush, uint32_t ttl)
Format TXT resource record.
uint32_t ttl
Definition: dns_common.h:221
unsigned int uint_t
Definition: compiler_port.h:50
#define osAtoi(s)
Definition: os_port.h:249
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:224
uint16_t priority
Definition: dns_common.h:265
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:544
@ 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:458
mDNS responder (Multicast DNS)
#define MDNS_RCLASS_CACHE_FLUSH
Definition: mdns_common.h:62
systime_t osGetSystemTime(void)
Retrieve system time.