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-2026 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.6.0
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
73  netUnlock(context->netContext);
74  //Invoke user callback function
75  context->stateChangeEvent(service, context->interface, newState);
76  //Get exclusive access
77  netLock(context->netContext);
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  uint8_t *p;
878  DnsResourceRecord *record;
879 
880  //Set the position to the end of the buffer
881  p = (uint8_t *) message->dnsHeader + message->length;
882  offset = message->length;
883 
884  //The first pass calculates the length of the DNS encoded service name
885  n = mdnsEncodeName("", service->serviceName, ".local", NULL);
886 
887  //Sanity check
888  if((message->length + n) > MDNS_MESSAGE_MAX_SIZE)
889  return ERROR_MESSAGE_TOO_LONG;
890 
891  //The second pass encodes the service name using DNS notation
892  n = mdnsEncodeName("", service->serviceName, ".local", p);
893 
894  //Check whether the resource record is already present in the Answer
895  //Section of the message
896  duplicate = mdnsCheckDuplicateRecord(message, "", "_services._dns-sd._udp",
897  ".local", DNS_RR_TYPE_PTR, p, n);
898 
899  //The duplicates should be suppressed and the resource record should
900  //appear only once in the list
901  if(!duplicate)
902  {
903  //Set the position to the end of the buffer
904  offset = message->length;
905 
906  //The first pass calculates the length of the DNS encoded service name
907  n = mdnsEncodeName("", "_services._dns-sd._udp", ".local", NULL);
908 
909  //Check the length of the resulting mDNS message
910  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
911  return ERROR_MESSAGE_TOO_LONG;
912 
913  //The second pass encodes the service name using the DNS name notation
914  offset += mdnsEncodeName("", "_services._dns-sd._udp", ".local",
915  (uint8_t *) message->dnsHeader + offset);
916 
917  //Consider the length of the resource record itself
918  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
919  return ERROR_MESSAGE_TOO_LONG;
920 
921  //Point to the corresponding resource record
922  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
923 
924  //Fill in resource record
925  record->rtype = HTONS(DNS_RR_TYPE_PTR);
926  record->rclass = HTONS(DNS_RR_CLASS_IN);
927  record->ttl = htonl(ttl);
928 
929  //Advance write index
930  offset += sizeof(DnsResourceRecord);
931 
932  //The first pass calculates the length of the DNS encoded service name
933  n = mdnsEncodeName("", service->serviceName, ".local", NULL);
934 
935  //Check the length of the resulting mDNS message
936  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
937  return ERROR_MESSAGE_TOO_LONG;
938 
939  //The second pass encodes the service name using DNS notation
940  n = mdnsEncodeName("", service->serviceName, ".local", record->rdata);
941 
942  //Convert length field to network byte order
943  record->rdlength = htons(n);
944 
945  //Number of resource records in the answer section
946  message->dnsHeader->ancount++;
947  //Update the length of the DNS message
948  message->length = offset + n;
949  }
950 
951  //Successful processing
952  return NO_ERROR;
953 }
954 
955 
956 /**
957  * @brief Format PTR resource record
958  * @param[in] interface Underlying network interface
959  * @param[in,out] message Pointer to the mDNS message
960  * @param[in] service Pointer to a DNS-SD service
961  * @param[in] ttl Resource record TTL (cache lifetime)
962  * @return Error code
963  **/
964 
966  MdnsMessage *message, const DnsSdResponderService *service, uint32_t ttl)
967 {
968  size_t n;
969  size_t offset;
970  bool_t duplicate;
971  uint8_t *p;
972  DnsResourceRecord *record;
973 
974  //Set the position to the end of the buffer
975  p = (uint8_t *) message->dnsHeader + message->length;
976  offset = message->length;
977 
978  //The first pass calculates the length of the DNS encoded instance name
979  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
980  NULL);
981 
982  //Sanity check
983  if((message->length + n) > MDNS_MESSAGE_MAX_SIZE)
984  return ERROR_MESSAGE_TOO_LONG;
985 
986  //The second pass encodes the instance name using DNS notation
987  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local", p);
988 
989  //Check whether the resource record is already present in the Answer
990  //Section of the message
991  duplicate = mdnsCheckDuplicateRecord(message, "", service->serviceName,
992  ".local", DNS_RR_TYPE_PTR, p, n);
993 
994  //The duplicates should be suppressed and the resource record should
995  //appear only once in the list
996  if(!duplicate)
997  {
998  //The first pass calculates the length of the DNS encoded service name
999  n = mdnsEncodeName("", service->serviceName, ".local", NULL);
1000 
1001  //Check the length of the resulting mDNS message
1002  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1003  return ERROR_MESSAGE_TOO_LONG;
1004 
1005  //The second pass encodes the service name using the DNS name notation
1006  offset += mdnsEncodeName("", service->serviceName, ".local", p);
1007 
1008  //Consider the length of the resource record itself
1009  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1010  return ERROR_MESSAGE_TOO_LONG;
1011 
1012  //Point to the corresponding resource record
1013  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1014 
1015  //Fill in resource record
1016  record->rtype = HTONS(DNS_RR_TYPE_PTR);
1017  record->rclass = HTONS(DNS_RR_CLASS_IN);
1018  record->ttl = htonl(ttl);
1019 
1020  //Advance write index
1021  offset += sizeof(DnsResourceRecord);
1022 
1023  //The first pass calculates the length of the DNS encoded instance name
1024  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1025  NULL);
1026 
1027  //Check the length of the resulting mDNS message
1028  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1029  return ERROR_MESSAGE_TOO_LONG;
1030 
1031  //The second pass encodes the instance name using DNS notation
1032  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1033  record->rdata);
1034 
1035  //Convert length field to network byte order
1036  record->rdlength = htons(n);
1037 
1038  //Number of resource records in the answer section
1039  message->dnsHeader->ancount++;
1040  //Update the length of the DNS message
1041  message->length = offset + n;
1042  }
1043 
1044  //Successful processing
1045  return NO_ERROR;
1046 }
1047 
1048 
1049 /**
1050  * @brief Format SRV resource record
1051  * @param[in] interface Underlying network interface
1052  * @param[in,out] message Pointer to the mDNS message
1053  * @param[in] service Pointer to a DNS-SD service
1054  * @param[in] cacheFlush Cache-flush bit
1055  * @param[in] ttl Resource record TTL (cache lifetime)
1056  * @return Error code
1057  **/
1058 
1060  MdnsMessage *message, const DnsSdResponderService *service,
1061  bool_t cacheFlush, uint32_t ttl)
1062 {
1063  size_t n;
1064  size_t offset;
1065  bool_t duplicate;
1066  MdnsResponderContext *mdnsResponderContext;
1067  DnsSrvResourceRecord *record;
1068 
1069  //Point to the mDNS responder context
1070  mdnsResponderContext = interface->mdnsResponderContext;
1071 
1072  //Check whether the resource record is already present in the Answer
1073  //Section of the message
1074  duplicate = mdnsCheckDuplicateRecord(message, service->instanceName,
1075  service->serviceName, ".local", DNS_RR_TYPE_SRV, NULL, 0);
1076 
1077  //The duplicates should be suppressed and the resource record should
1078  //appear only once in the list
1079  if(!duplicate)
1080  {
1081  //Set the position to the end of the buffer
1082  offset = message->length;
1083 
1084  //The first pass calculates the length of the DNS encoded instance name
1085  n = mdnsEncodeName(service->instanceName, service->serviceName,
1086  ".local", NULL);
1087 
1088  //Check the length of the resulting mDNS message
1089  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1090  return ERROR_MESSAGE_TOO_LONG;
1091 
1092  //The second pass encodes the instance name using DNS notation
1093  offset += mdnsEncodeName(service->instanceName, service->serviceName,
1094  ".local", (uint8_t *) message->dnsHeader + offset);
1095 
1096  //Consider the length of the resource record itself
1097  if((offset + sizeof(DnsSrvResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1098  return ERROR_MESSAGE_TOO_LONG;
1099 
1100  //Point to the corresponding resource record
1101  record = (DnsSrvResourceRecord *) DNS_GET_RESOURCE_RECORD(message->dnsHeader,
1102  offset);
1103 
1104  //Fill in resource record
1105  record->rtype = HTONS(DNS_RR_TYPE_SRV);
1106  record->rclass = HTONS(DNS_RR_CLASS_IN);
1107  record->ttl = htonl(ttl);
1108  record->priority = htons(service->priority);
1109  record->weight = htons(service->weight);
1110  record->port = htons(service->port);
1111 
1112  //Check whether the cache-flush bit should be set
1113  if(cacheFlush)
1114  {
1115  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1116  }
1117 
1118  //Advance write index
1119  offset += sizeof(DnsSrvResourceRecord);
1120 
1121  //The first pass calculates the length of the DNS encoded target name
1122  n = mdnsEncodeName("", mdnsResponderContext->hostname, ".local", NULL);
1123 
1124  //Check the length of the resulting mDNS message
1125  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1126  return ERROR_MESSAGE_TOO_LONG;
1127 
1128  //The second pass encodes the target name using DNS notation
1129  n = mdnsEncodeName("", mdnsResponderContext->hostname, ".local",
1130  record->target);
1131 
1132  //Calculate data length
1133  record->rdlength = htons(sizeof(DnsSrvResourceRecord) -
1134  sizeof(DnsResourceRecord) + n);
1135 
1136  //Number of resource records in the answer section
1137  message->dnsHeader->ancount++;
1138  //Update the length of the DNS message
1139  message->length = offset + n;
1140  }
1141 
1142  //Successful processing
1143  return NO_ERROR;
1144 }
1145 
1146 
1147 /**
1148  * @brief Format TXT resource record
1149  * @param[in] interface Underlying network interface
1150  * @param[in,out] message Pointer to the mDNS message
1151  * @param[in] service Pointer to a DNS-SD service
1152  * @param[in] cacheFlush Cache-flush bit
1153  * @param[in] ttl Resource record TTL (cache lifetime)
1154  * @return Error code
1155  **/
1156 
1158  MdnsMessage *message, const DnsSdResponderService *service,
1159  bool_t cacheFlush, uint32_t ttl)
1160 {
1161  size_t n;
1162  size_t offset;
1163  bool_t duplicate;
1164  DnsResourceRecord *record;
1165 
1166  //Check whether the resource record is already present in the Answer
1167  //Section of the message
1168  duplicate = mdnsCheckDuplicateRecord(message, service->instanceName,
1169  service->serviceName, ".local", DNS_RR_TYPE_TXT, NULL, 0);
1170 
1171  //The duplicates should be suppressed and the resource record should
1172  //appear only once in the list
1173  if(!duplicate)
1174  {
1175  //Set the position to the end of the buffer
1176  offset = message->length;
1177 
1178  //The first pass calculates the length of the DNS encoded instance name
1179  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1180  NULL);
1181 
1182  //Check the length of the resulting mDNS message
1183  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1184  return ERROR_MESSAGE_TOO_LONG;
1185 
1186  //The second pass encodes the instance name using DNS notation
1187  offset += mdnsEncodeName(service->instanceName, service->serviceName,
1188  ".local", (uint8_t *) message->dnsHeader + offset);
1189 
1190  //Consider the length of the resource record itself
1191  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1192  return ERROR_MESSAGE_TOO_LONG;
1193 
1194  //Point to the corresponding resource record
1195  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1196 
1197  //Fill in resource record
1198  record->rtype = HTONS(DNS_RR_TYPE_TXT);
1199  record->rclass = HTONS(DNS_RR_CLASS_IN);
1200  record->ttl = htonl(ttl);
1201  record->rdlength = htons(service->metadataLen);
1202 
1203  //Check whether the cache-flush bit should be set
1204  if(cacheFlush)
1205  {
1206  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1207  }
1208 
1209  //Advance write index
1210  offset += sizeof(DnsResourceRecord);
1211 
1212  //Check the length of the resulting mDNS message
1213  if((offset + service->metadataLen) > MDNS_MESSAGE_MAX_SIZE)
1214  return ERROR_MESSAGE_TOO_LONG;
1215 
1216  //Copy metadata
1217  osMemcpy(record->rdata, service->metadata, service->metadataLen);
1218 
1219  //Update the length of the DNS message
1220  message->length = offset + service->metadataLen;
1221  //Number of resource records in the answer section
1222  message->dnsHeader->ancount++;
1223  }
1224 
1225  //Successful processing
1226  return NO_ERROR;
1227 }
1228 
1229 
1230 /**
1231  * @brief Format NSEC resource record
1232  * @param[in] interface Underlying network interface
1233  * @param[in,out] message Pointer to the mDNS message
1234  * @param[in] service Pointer to a DNS-SD service
1235  * @param[in] cacheFlush Cache-flush bit
1236  * @param[in] ttl Resource record TTL (cache lifetime)
1237  * @return Error code
1238  **/
1239 
1241  MdnsMessage *message, const DnsSdResponderService *service,
1242  bool_t cacheFlush, uint32_t ttl)
1243 {
1244  size_t n;
1245  size_t offset;
1246  bool_t duplicate;
1247  size_t bitmapLen;
1248  uint8_t bitmap[8];
1249  DnsResourceRecord *record;
1250 
1251  //Check whether the resource record is already present in the Answer
1252  //Section of the message
1253  duplicate = mdnsCheckDuplicateRecord(message, service->instanceName,
1254  service->serviceName, ".local", DNS_RR_TYPE_NSEC, NULL, 0);
1255 
1256  //The duplicates should be suppressed and the resource record should
1257  //appear only once in the list
1258  if(!duplicate)
1259  {
1260  //The bitmap identifies the resource record types that exist
1261  osMemset(bitmap, 0, sizeof(bitmap));
1262 
1263  //TXT resource record is supported
1265  //SRV resource record is supported
1267 
1268  //Compute the length of the bitmap
1269  for(bitmapLen = sizeof(bitmap); bitmapLen > 0; bitmapLen--)
1270  {
1271  //Trailing zero octets in the bitmap must be omitted
1272  if(bitmap[bitmapLen - 1] != 0)
1273  {
1274  break;
1275  }
1276  }
1277 
1278  //Set the position to the end of the buffer
1279  offset = message->length;
1280 
1281  //The first pass calculates the length of the DNS encoded instance name
1282  n = mdnsEncodeName(service->instanceName, service->serviceName, ".local",
1283  NULL);
1284 
1285  //Check the length of the resulting mDNS message
1286  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1287  return ERROR_MESSAGE_TOO_LONG;
1288 
1289  //The second pass encodes the instance name using the DNS name notation
1290  offset += mdnsEncodeName(service->instanceName, service->serviceName,
1291  ".local", (uint8_t *) message->dnsHeader + offset);
1292 
1293  //Consider the length of the resource record itself
1294  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1295  return ERROR_MESSAGE_TOO_LONG;
1296 
1297  //Point to the corresponding resource record
1298  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1299 
1300  //Fill in resource record
1301  record->rtype = HTONS(DNS_RR_TYPE_NSEC);
1302  record->rclass = HTONS(DNS_RR_CLASS_IN);
1303  record->ttl = htonl(ttl);
1304 
1305  //Check whether the cache-flush bit should be set
1306  if(cacheFlush)
1307  {
1308  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1309  }
1310 
1311  //Advance write index
1312  offset += sizeof(DnsResourceRecord);
1313 
1314  //Check the length of the resulting mDNS message
1315  if((offset + n + 2) > MDNS_MESSAGE_MAX_SIZE)
1316  return ERROR_MESSAGE_TOO_LONG;
1317 
1318  //The Next Domain Name field contains the record's own name
1319  mdnsEncodeName(service->instanceName, service->serviceName,
1320  ".local", record->rdata);
1321 
1322  //DNS NSEC record is limited to Window Block number zero
1323  record->rdata[n++] = 0;
1324  //The Bitmap Length is a value in the range 1-32
1325  record->rdata[n++] = bitmapLen;
1326 
1327  //The Bitmap data identifies the resource record types that exist
1328  osMemcpy(record->rdata + n, bitmap, bitmapLen);
1329 
1330  //Convert length field to network byte order
1331  record->rdlength = htons(n + bitmapLen);
1332 
1333  //Number of resource records in the answer section
1334  message->dnsHeader->ancount++;
1335  //Update the length of the DNS message
1336  message->length = offset + n + bitmapLen;
1337  }
1338 
1339  //Successful processing
1340  return NO_ERROR;
1341 }
1342 
1343 
1344 /**
1345  * @brief Sort the tiebreaker records in lexicographical order
1346  * @param[in] service Pointer to a DNS-SD service
1347  * @param[in] query Incoming mDNS query message
1348  * @param[in] offset Offset to first byte of the Authority Section
1349  * @param[in] record Pointer to the current record
1350  * @return Pointer to the next record, if any
1351  **/
1352 
1354  DnsSdResponderService *service, const MdnsMessage *query, size_t offset,
1355  DnsResourceRecord *record)
1356 {
1357  uint_t i;
1358  size_t n;
1359  int_t res;
1360  DnsResourceRecord *curRecord;
1361  DnsResourceRecord *nextRecord;
1362 
1363  //Initialize record pointer
1364  nextRecord = NULL;
1365 
1366  //Parse Authority Section
1367  for(i = 0; i < ntohs(query->dnsHeader->nscount); i++)
1368  {
1369  //Parse resource record name
1370  n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
1371  //Invalid name?
1372  if(!n)
1373  break;
1374 
1375  //Point to the associated resource record
1376  curRecord = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
1377  //Point to the resource data
1378  n += sizeof(DnsResourceRecord);
1379 
1380  //Make sure the resource record is valid
1381  if(n > query->length)
1382  break;
1383  if((n + ntohs(curRecord->rdlength)) > query->length)
1384  break;
1385 
1386  //Matching host name?
1387  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
1388  service->instanceName, service->serviceName, ".local", 0))
1389  {
1390  //Perform lexicographical comparison
1391  if(record != NULL)
1392  {
1393  res = mdnsCompareRecord(query, curRecord, query, record);
1394  }
1395  else
1396  {
1397  res = 1;
1398  }
1399 
1400  //Check whether the record is lexicographically later
1401  if(res > 0)
1402  {
1403  if(nextRecord == NULL)
1404  {
1405  nextRecord = curRecord;
1406  }
1407  else if(mdnsCompareRecord(query, curRecord, query, nextRecord) < 0)
1408  {
1409  nextRecord = curRecord;
1410  }
1411  }
1412  }
1413 
1414  //Point to the next resource record
1415  offset = n + ntohs(curRecord->rdlength);
1416  }
1417 
1418  //Return the pointer to the next record
1419  return nextRecord;
1420 }
1421 
1422 
1423 /**
1424  * @brief Compare SRV resource records
1425  * @param[in] interface Underlying network interface
1426  * @param[in] service Pointer to a DNS-SD service
1427  * @param[in] message Pointer to mDNS message
1428  * @param[in] record Pointer the resource record
1429  * @return The function returns 0 if the resource record match the SRV resource
1430  * record of the host, -1 if the resource record lexicographically precedes
1431  * it, or 1 if the resource record lexicographically precedes it
1432  **/
1433 
1435  DnsSdResponderService *service, const MdnsMessage *message,
1436  const DnsResourceRecord *record)
1437 {
1438  int_t res;
1439  size_t offset;
1440  uint16_t value;
1441  MdnsResponderContext *mdnsResponderContext;
1442  DnsSrvResourceRecord *srvRecord;
1443 
1444  //Point to the mDNS responder context
1445  mdnsResponderContext = interface->mdnsResponderContext;
1446 
1447  //Convert the record class to host byte order
1448  value = ntohs(record->rclass);
1449  //Discard cache-flush bit
1451 
1452  //The determination of lexicographically later record is performed by
1453  //first comparing the record class (excluding the cache-flush bit)
1454  if(value < DNS_RR_CLASS_IN)
1455  {
1456  return -1;
1457  }
1458  else if(value > DNS_RR_CLASS_IN)
1459  {
1460  return 1;
1461  }
1462  else
1463  {
1464  }
1465 
1466  //Convert the record type to host byte order
1467  value = ntohs(record->rtype);
1468 
1469  //Then compare the record type
1470  if(value < DNS_RR_TYPE_SRV)
1471  {
1472  return -1;
1473  }
1474  else if(value > DNS_RR_TYPE_SRV)
1475  {
1476  return 1;
1477  }
1478  else
1479  {
1480  }
1481 
1482  //If the rrtype and rrclass both match, then the rdata is compared
1483  srvRecord = (DnsSrvResourceRecord *) record;
1484  //Convert the Priority field to host byte order
1485  value = ntohs(srvRecord->priority);
1486 
1487  //Compare Priority fields
1488  if(value < service->priority)
1489  {
1490  return -1;
1491  }
1492  else if(value > service->priority)
1493  {
1494  return 1;
1495  }
1496  else
1497  {
1498  }
1499 
1500  //Convert the Weight field to host byte order
1501  value = ntohs(srvRecord->weight);
1502 
1503  //Compare Weight fields
1504  if(value < service->weight)
1505  {
1506  return -1;
1507  }
1508  else if(value > service->weight)
1509  {
1510  return 1;
1511  }
1512  else
1513  {
1514  }
1515 
1516  //Convert the Port field to host byte order
1517  value = ntohs(srvRecord->port);
1518 
1519  //Compare Port fields
1520  if(value < service->port)
1521  {
1522  return -1;
1523  }
1524  else if(value > service->port)
1525  {
1526  return 1;
1527  }
1528  else
1529  {
1530  }
1531 
1532  //Compute the offset of the first byte of the Target field
1533  offset = srvRecord->target - (uint8_t *) message->dnsHeader;
1534 
1535  //Compare Target fields
1536  res = mdnsCompareName(message->dnsHeader, message->length, offset,
1537  "", mdnsResponderContext->hostname, ".local", 0);
1538 
1539  //Return comparison result
1540  return res;
1541 }
1542 
1543 
1544 /**
1545  * @brief Compare TXT resource records
1546  * @param[in] service Pointer to a DNS-SD service
1547  * @param[in] message Pointer to mDNS message
1548  * @param[in] record Pointer the resource record
1549  * @return The function returns 0 if the resource record match the TXT resource
1550  * record of the host, -1 if the resource record lexicographically precedes
1551  * it, or 1 if the resource record lexicographically precedes it
1552  **/
1553 
1555  const MdnsMessage *message, const DnsResourceRecord *record)
1556 {
1557  int_t res;
1558  size_t n;
1559  uint16_t value;
1560 
1561  //Convert the record class to host byte order
1562  value = ntohs(record->rclass);
1563  //Discard cache-flush bit
1565 
1566  //The determination of lexicographically later record is performed by
1567  //first comparing the record class (excluding the cache-flush bit)
1568  if(value < DNS_RR_CLASS_IN)
1569  {
1570  return -1;
1571  }
1572  else if(value > DNS_RR_CLASS_IN)
1573  {
1574  return 1;
1575  }
1576  else
1577  {
1578  }
1579 
1580  //Convert the record type to host byte order
1581  value = ntohs(record->rtype);
1582 
1583  //Then compare the record type
1584  if(value < DNS_RR_TYPE_TXT)
1585  {
1586  return -1;
1587  }
1588  else if(value > DNS_RR_TYPE_TXT)
1589  {
1590  return 1;
1591  }
1592  else
1593  {
1594  }
1595 
1596  //Retrieve the length of the rdata fields
1597  n = htons(record->rdlength);
1598 
1599  //The bytes of the raw uncompressed rdata are compared in turn, interpreting
1600  //the bytes as eight-bit unsigned values, until a byte is found whose value
1601  //is greater than that of its counterpart (in which case, the rdata whose
1602  //byte has the greater value is deemed lexicographically later) or one of the
1603  //resource records runs out of rdata (in which case, the resource record which
1604  //still has remaining data first is deemed lexicographically later)
1605  if(n < service->metadataLen)
1606  {
1607  //Raw comparison of the binary content of the rdata
1608  res = osMemcmp(record->rdata, service->metadata, n);
1609 
1610  //Check comparison result
1611  if(!res)
1612  {
1613  //The first resource records runs out of rdata
1614  res = -1;
1615  }
1616  }
1617  else if(n > service->metadataLen)
1618  {
1619  //Raw comparison of the binary content of the rdata
1620  res = osMemcmp(record->rdata, service->metadata, service->metadataLen);
1621 
1622  //Check comparison result
1623  if(!res)
1624  {
1625  //The second resource records runs out of rdata
1626  res = 1;
1627  }
1628  }
1629  else
1630  {
1631  //Raw comparison of the binary content of the rdata
1632  res = osMemcmp(record->rdata, service->metadata, n);
1633  }
1634 
1635  //Return comparison result
1636  return res;
1637 }
1638 
1639 #endif
#define MdnsResponderContext
#define htons(value)
Definition: cpu_endian.h:413
error_t dnsSdResponderSendGoodbye(DnsSdResponderService *service)
Send goodbye packet.
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
int bool_t
Definition: compiler_port.h:63
@ DNS_RR_CLASS_ANY
Any class.
Definition: dns_common.h:127
DnsSrvResourceRecord
Definition: dns_common.h:272
signed int int_t
Definition: compiler_port.h:56
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:269
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:153
error_t dnsSdResponderSendAnnouncement(DnsSdResponderService *service)
Send announcement packet.
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
DnsHeader * dnsHeader
Definition: mdns_common.h:84
uint16_t rclass
Definition: dns_common.h:223
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:124
DnsHeader
Definition: dns_common.h:202
#define osStrlen(s)
Definition: os_port.h:168
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:158
#define FALSE
Definition: os_port.h:46
#define htonl(value)
Definition: cpu_endian.h:414
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
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:234
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:212
error_t dnsSdResponderFormatPtrRecord(NetInterface *interface, MdnsMessage *message, const DnsSdResponderService *service, uint32_t ttl)
Format PTR resource record.
#define NetInterface
Definition: net.h:40
#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:198
#define DnsSdResponderService
#define osIsdigit(c)
Definition: os_port.h:288
#define DNS_SD_MAX_INSTANCE_NAME_LEN
@ ERROR_MESSAGE_TOO_LONG
Definition: error.h:137
#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:270
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:55
#define osStrcat(s1, s2)
Definition: os_port.h:222
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
@ DNS_RR_TYPE_TXT
Text strings.
Definition: dns_common.h:146
DnsQuestion
Definition: dns_common.h:213
#define MDNS_MESSAGE_MAX_SIZE
Definition: mdns_common.h:40
uint8_t value[]
Definition: tcp.h:376
uint8_t s
Definition: igmp_common.h:234
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
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:150
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:224
unsigned int uint_t
Definition: compiler_port.h:57
#define osAtoi(s)
Definition: os_port.h:252
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:227
uint16_t priority
Definition: dns_common.h:268
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.