Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
dns_sd.c
Go to the documentation of this file.
00001 /** 00002 * @file dns_sd.c 00003 * @brief DNS-SD (DNS-Based Service Discovery) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * DNS-SD allows clients to discover a list of named instances of that 00028 * desired service, using standard DNS queries. Refer to the following 00029 * RFCs for complete details: 00030 * - RFC 6763: DNS-Based Service Discovery 00031 * - RFC 2782: A DNS RR for specifying the location of services (DNS SRV) 00032 * 00033 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00034 * @version 1.7.6 00035 **/ 00036 00037 //Switch to the appropriate trace level 00038 #define TRACE_LEVEL DNS_SD_TRACE_LEVEL 00039 00040 //Dependencies 00041 #include <stdlib.h> 00042 #include <ctype.h> 00043 #include "core/net.h" 00044 #include "mdns/mdns_common.h" 00045 #include "mdns/mdns_responder.h" 00046 #include "dns/dns_debug.h" 00047 #include "dns_sd/dns_sd.h" 00048 #include "str.h" 00049 #include "debug.h" 00050 00051 //Check TCP/IP stack configuration 00052 #if (DNS_SD_SUPPORT == ENABLED) 00053 00054 //Tick counter to handle periodic operations 00055 systime_t dnsSdTickCounter; 00056 00057 00058 /** 00059 * @brief Initialize settings with default values 00060 * @param[out] settings Structure that contains DNS-SD settings 00061 **/ 00062 00063 void dnsSdGetDefaultSettings(DnsSdSettings *settings) 00064 { 00065 //Use default interface 00066 settings->interface = netGetDefaultInterface(); 00067 00068 //Number of announcement packets 00069 settings->numAnnouncements = MDNS_ANNOUNCE_NUM; 00070 //TTL resource record 00071 settings->ttl = DNS_SD_DEFAULT_RR_TTL; 00072 //FSM state change event 00073 settings->stateChangeEvent = NULL; 00074 } 00075 00076 00077 /** 00078 * @brief DNS-DS initialization 00079 * @param[in] context Pointer to the DNS-SD context 00080 * @param[in] settings DNS-SD specific settings 00081 * @return Error code 00082 **/ 00083 00084 error_t dnsSdInit(DnsSdContext *context, const DnsSdSettings *settings) 00085 { 00086 NetInterface *interface; 00087 00088 //Debug message 00089 TRACE_INFO("Initializing DNS-SD...\r\n"); 00090 00091 //Ensure the parameters are valid 00092 if(context == NULL || settings == NULL) 00093 return ERROR_INVALID_PARAMETER; 00094 00095 //Invalid network interface? 00096 if(settings->interface == NULL) 00097 return ERROR_INVALID_PARAMETER; 00098 00099 //Point to the underlying network interface 00100 interface = settings->interface; 00101 00102 //Clear the DNS-SD context 00103 memset(context, 0, sizeof(DnsSdContext)); 00104 //Save user settings 00105 context->settings = *settings; 00106 00107 //DNS-SD is currently suspended 00108 context->running = FALSE; 00109 //Initialize state machine 00110 context->state = MDNS_STATE_INIT; 00111 00112 //Attach the DNS-SD context to the network interface 00113 interface->dnsSdContext = context; 00114 00115 //Successful initialization 00116 return NO_ERROR; 00117 } 00118 00119 00120 /** 00121 * @brief Start mDNS responder 00122 * @param[in] context Pointer to the DNS-SD context 00123 * @return Error code 00124 **/ 00125 00126 error_t dnsSdStart(DnsSdContext *context) 00127 { 00128 //Check parameter 00129 if(context == NULL) 00130 return ERROR_INVALID_PARAMETER; 00131 00132 //Debug message 00133 TRACE_INFO("Starting DNS-SD...\r\n"); 00134 00135 //Get exclusive access 00136 osAcquireMutex(&netMutex); 00137 00138 //Start DNS-SD 00139 context->running = TRUE; 00140 //Initialize state machine 00141 context->state = MDNS_STATE_INIT; 00142 00143 //Release exclusive access 00144 osReleaseMutex(&netMutex); 00145 00146 //Successful processing 00147 return NO_ERROR; 00148 } 00149 00150 00151 /** 00152 * @brief Stop mDNS responder 00153 * @param[in] context Pointer to the DNS-SD context 00154 * @return Error code 00155 **/ 00156 00157 error_t dnsSdStop(DnsSdContext *context) 00158 { 00159 //Check parameter 00160 if(context == NULL) 00161 return ERROR_INVALID_PARAMETER; 00162 00163 //Debug message 00164 TRACE_INFO("Stopping DNS-SD...\r\n"); 00165 00166 //Get exclusive access 00167 osAcquireMutex(&netMutex); 00168 00169 //Suspend DNS-SD 00170 context->running = FALSE; 00171 //Reinitialize state machine 00172 context->state = MDNS_STATE_INIT; 00173 00174 //Release exclusive access 00175 osReleaseMutex(&netMutex); 00176 00177 //Successful processing 00178 return NO_ERROR; 00179 } 00180 00181 00182 /** 00183 * @brief Retrieve current state 00184 * @param[in] context Pointer to the DNS-SD context 00185 * @return Current DNS-SD state 00186 **/ 00187 00188 MdnsState dnsSdGetState(DnsSdContext *context) 00189 { 00190 MdnsState state; 00191 00192 //Get exclusive access 00193 osAcquireMutex(&netMutex); 00194 //Get current state 00195 state = context->state; 00196 //Release exclusive access 00197 osReleaseMutex(&netMutex); 00198 00199 //Return current state 00200 return state; 00201 } 00202 00203 00204 /** 00205 * @brief Set service instance name 00206 * @param[in] context Pointer to the DNS-SD context 00207 * @param[in] instanceName NULL-terminated string that contains the service 00208 * instance name 00209 * @return Error code 00210 **/ 00211 00212 error_t dnsSdSetInstanceName(DnsSdContext *context, const char_t *instanceName) 00213 { 00214 NetInterface *interface; 00215 00216 //Check parameters 00217 if(context == NULL || instanceName == NULL) 00218 return ERROR_INVALID_PARAMETER; 00219 00220 //Get exclusive access 00221 osAcquireMutex(&netMutex); 00222 00223 //Point to the underlying network interface 00224 interface = context->settings.interface; 00225 00226 //Any registered services? 00227 if(dnsSdGetNumServices(context) > 0) 00228 { 00229 //Check whether the link is up 00230 if(interface->linkState) 00231 { 00232 //Send a goodbye packet 00233 dnsSdSendGoodbye(context, NULL); 00234 } 00235 } 00236 00237 //Set instance name 00238 strSafeCopy(context->instanceName, instanceName, 00239 DNS_SD_MAX_INSTANCE_NAME_LEN); 00240 00241 //Restart probing process 00242 dnsSdStartProbing(context); 00243 00244 //Release exclusive access 00245 osReleaseMutex(&netMutex); 00246 00247 //Successful processing 00248 return NO_ERROR; 00249 } 00250 00251 00252 /** 00253 * @brief Register a DNS-SD service 00254 * @param[in] context Pointer to the DNS-SD context 00255 * @param[in] serviceName NULL-terminated string that contains the name of the 00256 * service to be registered 00257 * @param[in] priority Priority field 00258 * @param[in] weight Weight field 00259 * @param[in] port Port number 00260 * @param[in] metadata NULL-terminated string that contains the discovery-time 00261 * metadata (TXT record) 00262 * @return Error code 00263 **/ 00264 00265 error_t dnsSdRegisterService(DnsSdContext *context, const char_t *serviceName, 00266 uint16_t priority, uint16_t weight, uint16_t port, const char_t *metadata) 00267 { 00268 error_t error; 00269 size_t i; 00270 size_t j; 00271 size_t k; 00272 size_t n; 00273 DnsSdService *entry; 00274 DnsSdService *firstFreeEntry; 00275 00276 //Check parameters 00277 if(context == NULL || serviceName == NULL || metadata == NULL) 00278 return ERROR_INVALID_PARAMETER; 00279 00280 //Get exclusive access 00281 osAcquireMutex(&netMutex); 00282 00283 //Keep track of the first free entry 00284 firstFreeEntry = NULL; 00285 00286 //Loop through the list of registered services 00287 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 00288 { 00289 //Point to the current entry 00290 entry = &context->serviceList[i]; 00291 00292 //Check if the entry is currently in use 00293 if(entry->name[0] != '\0') 00294 { 00295 //Check whether the specified service is already registered 00296 if(!strcasecmp(entry->name, serviceName)) 00297 break; 00298 } 00299 else 00300 { 00301 //Keep track of the first free entry 00302 if(firstFreeEntry == NULL) 00303 firstFreeEntry = entry; 00304 } 00305 } 00306 00307 //If the specified service is not yet registered, then a new 00308 //entry should be created 00309 if(i >= DNS_SD_SERVICE_LIST_SIZE) 00310 entry = firstFreeEntry; 00311 00312 //Check whether the service list runs out of space 00313 if(entry != NULL) 00314 { 00315 //Service name 00316 strSafeCopy(entry->name, serviceName, DNS_SD_MAX_SERVICE_NAME_LEN); 00317 00318 //Priority field 00319 entry->priority = priority; 00320 //Weight field 00321 entry->weight = weight; 00322 //Port number 00323 entry->port = port; 00324 00325 //Clear TXT record 00326 entry->metadataLength = 0; 00327 00328 //Point to the beginning of the information string 00329 i = 0; 00330 j = 0; 00331 00332 //Point to the beginning of the resulting TXT record data 00333 k = 0; 00334 00335 //Format TXT record 00336 while(1) 00337 { 00338 //End of text data? 00339 if(metadata[i] == '\0' || metadata[i] == ';') 00340 { 00341 //Calculate the length of the text data 00342 n = MIN(i - j, UINT8_MAX); 00343 00344 //Check the length of the resulting TXT record 00345 if((entry->metadataLength + n + 1) > DNS_SD_MAX_METADATA_LEN) 00346 break; 00347 00348 //Write length field 00349 entry->metadata[k] = n; 00350 //Write text data 00351 memcpy(entry->metadata + k + 1, metadata + j, n); 00352 00353 //Jump to the next text data 00354 j = i + 1; 00355 //Advance write index 00356 k += n + 1; 00357 00358 //Update the length of the TXT record 00359 entry->metadataLength += n + 1; 00360 00361 //End of string detected? 00362 if(metadata[i] == '\0') 00363 break; 00364 } 00365 00366 //Advance read index 00367 i++; 00368 } 00369 00370 //Empty TXT record? 00371 if(!entry->metadataLength) 00372 { 00373 //An empty TXT record shall contain a single zero byte 00374 entry->metadata[0] = 0; 00375 entry->metadataLength = 1; 00376 } 00377 00378 //Restart probing process 00379 dnsSdStartProbing(context); 00380 00381 //Successful processing 00382 error = NO_ERROR; 00383 } 00384 else 00385 { 00386 //The service list is full 00387 error = ERROR_FAILURE; 00388 } 00389 00390 //Release exclusive access 00391 osReleaseMutex(&netMutex); 00392 00393 //Return error code 00394 return error; 00395 } 00396 00397 00398 /** 00399 * @brief Unregister a DNS-SD service 00400 * @param[in] context Pointer to the DNS-SD context 00401 * @param[in] serviceName NULL-terminated string that contains the name of the 00402 * service to be unregistered 00403 * @return Error code 00404 **/ 00405 00406 error_t dnsSdUnregisterService(DnsSdContext *context, const char_t *serviceName) 00407 { 00408 uint_t i; 00409 DnsSdService *entry; 00410 00411 //Check parameters 00412 if(context == NULL || serviceName == NULL) 00413 return ERROR_INVALID_PARAMETER; 00414 00415 //Get exclusive access 00416 osAcquireMutex(&netMutex); 00417 00418 //Loop through the list of registered services 00419 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 00420 { 00421 //Point to the current entry 00422 entry = &context->serviceList[i]; 00423 00424 //Service name found? 00425 if(!strcasecmp(entry->name, serviceName)) 00426 { 00427 //Send a goodbye packet 00428 dnsSdSendGoodbye(context, entry); 00429 //Remove the service from the list 00430 entry->name[0] = '\0'; 00431 } 00432 } 00433 00434 //Release exclusive access 00435 osReleaseMutex(&netMutex); 00436 00437 //Successful processing 00438 return NO_ERROR; 00439 } 00440 00441 00442 /** 00443 * @brief Get the number of registered services 00444 * @param[in] context Pointer to the DNS-SD context 00445 * @return Number of registered services 00446 **/ 00447 00448 uint_t dnsSdGetNumServices(DnsSdContext *context) 00449 { 00450 uint_t i; 00451 uint_t n; 00452 00453 //Number of registered services 00454 n = 0; 00455 00456 //Check parameter 00457 if(context != NULL) 00458 { 00459 //Valid instance name? 00460 if(context->instanceName[0] != '\0') 00461 { 00462 //Loop through the list of registered services 00463 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 00464 { 00465 //Check if the entry is currently in use 00466 if(context->serviceList[i].name[0] != '\0') 00467 n++; 00468 } 00469 } 00470 } 00471 00472 //Return the number of registered services 00473 return n; 00474 } 00475 00476 00477 /** 00478 * @brief Restart probing process 00479 * @param[in] context Pointer to the DNS-SD context 00480 * @return Error code 00481 **/ 00482 00483 error_t dnsSdStartProbing(DnsSdContext *context) 00484 { 00485 //Check parameter 00486 if(context == NULL) 00487 return ERROR_INVALID_PARAMETER; 00488 00489 //Force DNS-SD to start probing again 00490 context->state = MDNS_STATE_INIT; 00491 00492 //Successful processing 00493 return NO_ERROR; 00494 } 00495 00496 00497 /** 00498 * @brief DNS-SD responder timer handler 00499 * 00500 * This routine must be periodically called by the TCP/IP stack to 00501 * manage DNS-SD operation 00502 * 00503 * @param[in] context Pointer to the DNS-SD context 00504 **/ 00505 00506 void dnsSdTick(DnsSdContext *context) 00507 { 00508 systime_t time; 00509 systime_t delay; 00510 NetInterface *interface; 00511 MdnsState state; 00512 00513 //Make sure DNS-SD has been properly instantiated 00514 if(context == NULL) 00515 return; 00516 00517 //Point to the underlying network interface 00518 interface = context->settings.interface; 00519 00520 //Get current time 00521 time = osGetSystemTime(); 00522 00523 //Check current state 00524 if(context->state == MDNS_STATE_INIT) 00525 { 00526 //Check whether the mDNS responder has been properly instantiated 00527 if(interface->mdnsResponderContext != NULL) 00528 state = interface->mdnsResponderContext->state; 00529 else 00530 state = MDNS_STATE_INIT; 00531 00532 //Wait for mDNS probing to complete 00533 if(state == MDNS_STATE_ANNOUNCING || state == MDNS_STATE_IDLE) 00534 { 00535 //Any registered services? 00536 if(dnsSdGetNumServices(context) > 0) 00537 { 00538 //Initial random delay 00539 delay = netGetRandRange(MDNS_RAND_DELAY_MIN, MDNS_RAND_DELAY_MAX); 00540 //Perform probing 00541 dnsSdChangeState(context, MDNS_STATE_PROBING, delay); 00542 } 00543 } 00544 } 00545 else if(context->state == MDNS_STATE_PROBING) 00546 { 00547 //Probing failed? 00548 if(context->conflict && context->retransmitCount > 0) 00549 { 00550 //Programmatically change the service instance name 00551 dnsSdChangeInstanceName(context); 00552 //Probe again, and repeat as necessary until a unique name is found 00553 dnsSdChangeState(context, MDNS_STATE_PROBING, 0); 00554 } 00555 //Tie-break lost? 00556 else if(context->tieBreakLost && context->retransmitCount > 0) 00557 { 00558 //The host defers to the winning host by waiting one second, and 00559 //then begins probing for this record again 00560 dnsSdChangeState(context, MDNS_STATE_PROBING, MDNS_PROBE_DEFER); 00561 } 00562 else 00563 { 00564 //Check current time 00565 if(timeCompare(time, context->timestamp + context->timeout) >= 0) 00566 { 00567 //Probing is on-going? 00568 if(context->retransmitCount < MDNS_PROBE_NUM) 00569 { 00570 //First probe? 00571 if(context->retransmitCount == 0) 00572 { 00573 //Apparently conflicting mDNS responses received before the 00574 //first probe packet is sent must be silently ignored 00575 context->conflict = FALSE; 00576 context->tieBreakLost = FALSE; 00577 } 00578 00579 //Send probe packet 00580 dnsSdSendProbe(context); 00581 00582 //Save the time at which the packet was sent 00583 context->timestamp = time; 00584 //Time interval between subsequent probe packets 00585 context->timeout = MDNS_PROBE_DELAY; 00586 //Increment retransmission counter 00587 context->retransmitCount++; 00588 } 00589 //Probing is complete? 00590 else 00591 { 00592 //The mDNS responder must send unsolicited mDNS responses 00593 //containing all of its newly registered resource records 00594 if(context->settings.numAnnouncements > 0) 00595 dnsSdChangeState(context, MDNS_STATE_ANNOUNCING, 0); 00596 else 00597 dnsSdChangeState(context, MDNS_STATE_IDLE, 0); 00598 } 00599 } 00600 } 00601 } 00602 else if(context->state == MDNS_STATE_ANNOUNCING) 00603 { 00604 //Whenever a mDNS responder receives any mDNS response (solicited or 00605 //otherwise) containing a conflicting resource record, the conflict 00606 //must be resolved 00607 if(context->conflict) 00608 { 00609 //Probe again, and repeat as necessary until a unique name is found 00610 dnsSdChangeState(context, MDNS_STATE_PROBING, 0); 00611 } 00612 else 00613 { 00614 //Check current time 00615 if(timeCompare(time, context->timestamp + context->timeout) >= 0) 00616 { 00617 //Send announcement packet 00618 dnsSdSendAnnouncement(context); 00619 00620 //Save the time at which the packet was sent 00621 context->timestamp = time; 00622 //Increment retransmission counter 00623 context->retransmitCount++; 00624 00625 //First announcement packet? 00626 if(context->retransmitCount == 1) 00627 { 00628 //The mDNS responder must send at least two unsolicited 00629 //responses, one second apart 00630 context->timeout = MDNS_ANNOUNCE_DELAY; 00631 } 00632 else 00633 { 00634 //To provide increased robustness against packet loss, a mDNS 00635 //responder may send up to eight unsolicited responses, provided 00636 //that the interval between unsolicited responses increases by 00637 //at least a factor of two with every response sent 00638 context->timeout *= 2; 00639 } 00640 00641 //Last announcement packet? 00642 if(context->retransmitCount >= context->settings.numAnnouncements) 00643 { 00644 //A mDNS responder must not send regular periodic announcements 00645 dnsSdChangeState(context, MDNS_STATE_IDLE, 0); 00646 } 00647 } 00648 } 00649 } 00650 else if(context->state == MDNS_STATE_IDLE) 00651 { 00652 //Whenever a mDNS responder receives any mDNS response (solicited or 00653 //otherwise) containing a conflicting resource record, the conflict 00654 //must be resolved 00655 if(context->conflict) 00656 { 00657 //Probe again, and repeat as necessary until a unique name is found 00658 dnsSdChangeState(context, MDNS_STATE_PROBING, 0); 00659 } 00660 } 00661 } 00662 00663 00664 /** 00665 * @brief Callback function for link change event 00666 * @param[in] context Pointer to the DNS-SD context 00667 **/ 00668 00669 void dnsSdLinkChangeEvent(DnsSdContext *context) 00670 { 00671 //Make sure DNS-SD has been properly instantiated 00672 if(context == NULL) 00673 return; 00674 00675 //Whenever a mDNS responder receives an indication of a link 00676 //change event, it must perform probing and announcing 00677 dnsSdChangeState(context, MDNS_STATE_INIT, 0); 00678 } 00679 00680 00681 /** 00682 * @brief Update FSM state 00683 * @param[in] context Pointer to the DNS-SD context 00684 * @param[in] newState New state to switch to 00685 * @param[in] delay Initial delay 00686 **/ 00687 00688 void dnsSdChangeState(DnsSdContext *context, 00689 MdnsState newState, systime_t delay) 00690 { 00691 NetInterface *interface; 00692 00693 //Point to the underlying network interface 00694 interface = context->settings.interface; 00695 00696 //Set time stamp 00697 context->timestamp = osGetSystemTime(); 00698 //Set initial delay 00699 context->timeout = delay; 00700 //Reset retransmission counter 00701 context->retransmitCount = 0; 00702 //Switch to the new state 00703 context->state = newState; 00704 00705 //Any registered callback? 00706 if(context->settings.stateChangeEvent != NULL) 00707 { 00708 //Release exclusive access 00709 osReleaseMutex(&netMutex); 00710 //Invoke user callback function 00711 context->settings.stateChangeEvent(context, interface, newState); 00712 //Get exclusive access 00713 osAcquireMutex(&netMutex); 00714 } 00715 } 00716 00717 00718 /** 00719 * @brief Programmatically change the service instance name 00720 * @param[in] context Pointer to the DNS-SD context 00721 **/ 00722 00723 void dnsSdChangeInstanceName(DnsSdContext *context) 00724 { 00725 size_t i; 00726 size_t m; 00727 size_t n; 00728 uint32_t index; 00729 char_t s[16]; 00730 00731 //Retrieve the length of the string 00732 n = strlen(context->instanceName); 00733 00734 //Parse the string backwards 00735 for(i = n; i > 0; i--) 00736 { 00737 //Last character? 00738 if(i == n) 00739 { 00740 //Check whether the last character is a bracket 00741 if(context->instanceName[i - 1] != ')') 00742 break; 00743 } 00744 else 00745 { 00746 //Check whether the current character is a digit 00747 if(!isdigit((uint8_t) context->instanceName[i - 1])) 00748 break; 00749 } 00750 } 00751 00752 //Any number following the service instance name? 00753 if(context->instanceName[i] != '\0') 00754 { 00755 //Retrieve the number at the end of the name 00756 index = atoi(context->instanceName + i); 00757 //Increment the value 00758 index++; 00759 00760 //Check the length of the name 00761 if(i >= 2) 00762 { 00763 //Discard any space and bracket that may precede the number 00764 if(context->instanceName[i - 2] == ' ' && 00765 context->instanceName[i - 1] == '(') 00766 { 00767 i -= 2; 00768 } 00769 } 00770 00771 //Strip the digits 00772 context->instanceName[i] = '\0'; 00773 } 00774 else 00775 { 00776 //Append the digit "2" to the name 00777 index = 2; 00778 } 00779 00780 //Convert the number to a string of characters 00781 m = sprintf(s, " (%" PRIu32 ")", index); 00782 00783 //Sanity check 00784 if((i + m) <= DNS_SD_MAX_INSTANCE_NAME_LEN) 00785 { 00786 //Programmatically change the service instance name 00787 strcat(context->instanceName, s); 00788 } 00789 } 00790 00791 00792 /** 00793 * @brief Send probe packet 00794 * @param[in] context Pointer to the DNS-SD context 00795 * @return Error code 00796 **/ 00797 00798 error_t dnsSdSendProbe(DnsSdContext *context) 00799 { 00800 error_t error; 00801 uint_t i; 00802 NetInterface *interface; 00803 DnsQuestion *dnsQuestion; 00804 DnsSdService *service; 00805 MdnsMessage message; 00806 00807 //Point to the underlying network interface 00808 interface = context->settings.interface; 00809 00810 //Create an empty mDNS query message 00811 error = mdnsCreateMessage(&message, FALSE); 00812 //Any error to report? 00813 if(error) 00814 return error; 00815 00816 //Start of exception handling block 00817 do 00818 { 00819 //For all those resource records that a mDNS responder desires to be 00820 //unique on the local link, it must send a mDNS query asking for those 00821 //resource records, to see if any of them are already in use 00822 if(dnsSdGetNumServices(context) > 0) 00823 { 00824 //Loop through the list of registered services 00825 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 00826 { 00827 //Point to the current entry 00828 service = &context->serviceList[i]; 00829 00830 //Valid service? 00831 if(service->name[0] != '\0') 00832 { 00833 //Encode the service name using DNS notation 00834 message.length += mdnsEncodeName(context->instanceName, service->name, 00835 ".local", (uint8_t *) message.dnsHeader + message.length); 00836 00837 //Point to the corresponding question structure 00838 dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length); 00839 00840 //The probes should be sent as QU questions with the unicast-response 00841 //bit set, to allow a defending host to respond immediately via unicast 00842 dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY); 00843 dnsQuestion->qclass = HTONS(MDNS_QCLASS_QU | DNS_RR_CLASS_IN); 00844 00845 //Update the length of the mDNS query message 00846 message.length += sizeof(DnsQuestion); 00847 00848 //Number of questions in the Question Section 00849 message.dnsHeader->qdcount++; 00850 } 00851 } 00852 } 00853 00854 //A probe query can be distinguished from a normal query by the fact that 00855 //a probe query contains a proposed record in the Authority Section that 00856 //answers the question in the Question Section 00857 if(dnsSdGetNumServices(context) > 0) 00858 { 00859 //Loop through the list of registered services 00860 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 00861 { 00862 //Point to the current entry 00863 service = &context->serviceList[i]; 00864 00865 //Valid service? 00866 if(service->name[0] != '\0') 00867 { 00868 //Format SRV resource record 00869 error = dnsSdAddSrvRecord(interface, &message, 00870 service, FALSE, DNS_SD_DEFAULT_RR_TTL); 00871 //Any error to report? 00872 if(error) 00873 break; 00874 00875 //Format TXT resource record 00876 error = dnsSdAddTxtRecord(interface, &message, 00877 service, FALSE, DNS_SD_DEFAULT_RR_TTL); 00878 //Any error to report? 00879 if(error) 00880 break; 00881 } 00882 } 00883 } 00884 00885 //Propagate exception if necessary 00886 if(error) 00887 break; 00888 00889 //Number of resource records in the Authority Section 00890 message.dnsHeader->nscount = message.dnsHeader->ancount; 00891 //Number of resource records in the Answer Section 00892 message.dnsHeader->ancount = 0; 00893 00894 //Send mDNS message 00895 error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT); 00896 00897 //End of exception handling block 00898 } while(0); 00899 00900 //Free previously allocated memory 00901 mdnsDeleteMessage(&message); 00902 00903 //Return status code 00904 return error; 00905 } 00906 00907 00908 /** 00909 * @brief Send announcement packet 00910 * @param[in] context Pointer to the DNS-SD context 00911 * @return Error code 00912 **/ 00913 00914 error_t dnsSdSendAnnouncement(DnsSdContext *context) 00915 { 00916 error_t error; 00917 uint_t i; 00918 NetInterface *interface; 00919 DnsSdService *service; 00920 MdnsMessage message; 00921 00922 //Point to the underlying network interface 00923 interface = context->settings.interface; 00924 00925 //Create an empty mDNS response message 00926 error = mdnsCreateMessage(&message, TRUE); 00927 //Any error to report? 00928 if(error) 00929 return error; 00930 00931 //Start of exception handling block 00932 do 00933 { 00934 //Send an unsolicited mDNS response containing, in the Answer Section, 00935 //all of its newly registered resource records 00936 if(dnsSdGetNumServices(context) > 0) 00937 { 00938 //Loop through the list of registered services 00939 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 00940 { 00941 //Point to the current entry 00942 service = &context->serviceList[i]; 00943 00944 //Valid service? 00945 if(service->name[0] != '\0') 00946 { 00947 //Format PTR resource record (service type enumeration) 00948 error = dnsSdAddServiceEnumPtrRecord(interface, 00949 &message, service, DNS_SD_DEFAULT_RR_TTL); 00950 //Any error to report? 00951 if(error) 00952 break; 00953 00954 //Format PTR resource record 00955 error = dnsSdAddPtrRecord(interface, &message, 00956 service, DNS_SD_DEFAULT_RR_TTL); 00957 //Any error to report? 00958 if(error) 00959 break; 00960 00961 //Format SRV resource record 00962 error = dnsSdAddSrvRecord(interface, &message, 00963 service, TRUE, DNS_SD_DEFAULT_RR_TTL); 00964 //Any error to report? 00965 if(error) 00966 break; 00967 00968 //Format TXT resource record 00969 error = dnsSdAddTxtRecord(interface, &message, 00970 service, TRUE, DNS_SD_DEFAULT_RR_TTL); 00971 //Any error to report? 00972 if(error) 00973 break; 00974 } 00975 } 00976 } 00977 00978 //Propagate exception if necessary 00979 if(error) 00980 break; 00981 00982 //Send mDNS message 00983 error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT); 00984 00985 //End of exception handling block 00986 } while(0); 00987 00988 //Free previously allocated memory 00989 mdnsDeleteMessage(&message); 00990 00991 //Return status code 00992 return error; 00993 } 00994 00995 00996 /** 00997 * @brief Send goodbye packet 00998 * @param[in] context Pointer to the DNS-SD context 00999 * @param[in] service Pointer to a DNS-SD service 01000 * @return Error code 01001 **/ 01002 01003 error_t dnsSdSendGoodbye(DnsSdContext *context, const DnsSdService *service) 01004 { 01005 error_t error; 01006 uint_t i; 01007 NetInterface *interface; 01008 DnsSdService *entry; 01009 MdnsMessage message; 01010 01011 //Point to the underlying network interface 01012 interface = context->settings.interface; 01013 01014 //Create an empty mDNS response message 01015 error = mdnsCreateMessage(&message, TRUE); 01016 //Any error to report? 01017 if(error) 01018 return error; 01019 01020 //Loop through the list of registered services 01021 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 01022 { 01023 //Point to the current entry 01024 entry = &context->serviceList[i]; 01025 01026 //Valid service? 01027 if(entry->name[0] != '\0') 01028 { 01029 if(service == entry || service == NULL) 01030 { 01031 //Format PTR resource record (service type enumeration) 01032 error = dnsSdAddServiceEnumPtrRecord(interface, &message, entry, 0); 01033 //Any error to report? 01034 if(error) 01035 break; 01036 01037 //Format PTR resource record 01038 error = dnsSdAddPtrRecord(interface, &message, entry, 0); 01039 //Any error to report? 01040 if(error) 01041 break; 01042 01043 //Format SRV resource record 01044 error = dnsSdAddSrvRecord(interface, &message, entry, TRUE, 0); 01045 //Any error to report? 01046 if(error) 01047 break; 01048 01049 //Format TXT resource record 01050 error = dnsSdAddTxtRecord(interface, &message, entry, TRUE, 0); 01051 //Any error to report? 01052 if(error) 01053 break; 01054 } 01055 } 01056 } 01057 01058 //Check status code 01059 if(!error) 01060 { 01061 //Send mDNS message 01062 error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT); 01063 } 01064 01065 //Free previously allocated memory 01066 mdnsDeleteMessage(&message); 01067 01068 //Return status code 01069 return error; 01070 } 01071 01072 01073 /** 01074 * @brief Parse a question 01075 * @param[in] interface Underlying network interface 01076 * @param[in] query Incoming mDNS query message 01077 * @param[in] offset Offset to first byte of the question 01078 * @param[in] question Pointer to the question 01079 * @param[in,out] response mDNS response message 01080 * @return Error code 01081 **/ 01082 01083 error_t dnsSdParseQuestion(NetInterface *interface, const MdnsMessage *query, 01084 size_t offset, const DnsQuestion *question, MdnsMessage *response) 01085 { 01086 error_t error; 01087 uint_t i; 01088 uint16_t qclass; 01089 uint16_t qtype; 01090 uint32_t ttl; 01091 bool_t cacheFlush; 01092 DnsSdContext *context; 01093 DnsSdService *service; 01094 01095 //Point to the DNS-SD context 01096 context = interface->dnsSdContext; 01097 //Make sure DNS-SD has been properly instantiated 01098 if(context == NULL) 01099 return NO_ERROR; 01100 01101 //Check the state of the mDNS responder 01102 if(context->state != MDNS_STATE_ANNOUNCING && 01103 context->state != MDNS_STATE_IDLE) 01104 { 01105 //Do not respond to mDNS queries during probing 01106 return NO_ERROR; 01107 } 01108 01109 //Convert the query class to host byte order 01110 qclass = ntohs(question->qclass); 01111 //Discard QU flag 01112 qclass &= ~MDNS_QCLASS_QU; 01113 01114 //Convert the query type to host byte order 01115 qtype = ntohs(question->qtype); 01116 01117 //Get the TTL resource record 01118 ttl = context->settings.ttl; 01119 01120 //Check whether the querier originating the query is a simple resolver 01121 if(ntohs(query->udpHeader->srcPort) != MDNS_PORT) 01122 { 01123 //The resource record TTL given in a legacy unicast response should 01124 //not be greater than ten seconds, even if the true TTL of the mDNS 01125 //resource record is higher 01126 ttl = MIN(ttl, MDNS_LEGACY_UNICAST_RR_TTL); 01127 01128 //The cache-flush bit must not be set in legacy unicast responses 01129 cacheFlush = FALSE; 01130 } 01131 else 01132 { 01133 //The cache-bit should be set for unique resource records 01134 cacheFlush = TRUE; 01135 } 01136 01137 //Any registered services? 01138 if(dnsSdGetNumServices(context) > 0) 01139 { 01140 //Loop through the list of registered services 01141 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 01142 { 01143 //Point to the current entry 01144 service = &context->serviceList[i]; 01145 01146 //Valid service? 01147 if(service->name[0] != '\0') 01148 { 01149 //Check the class of the query 01150 if(qclass == DNS_RR_CLASS_IN || qclass == DNS_RR_CLASS_ANY) 01151 { 01152 //Compare service name 01153 if(!mdnsCompareName(query->dnsHeader, query->length, 01154 offset, "", "_services._dns-sd._udp", ".local", 0)) 01155 { 01156 //PTR query? 01157 if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY) 01158 { 01159 //Format PTR resource record (service type enumeration) 01160 error = dnsSdAddServiceEnumPtrRecord(interface, 01161 response, service, ttl); 01162 //Any error to report? 01163 if(error) 01164 return error; 01165 01166 //Update the number of shared resource records 01167 response->sharedRecordCount++; 01168 } 01169 } 01170 else if(!mdnsCompareName(query->dnsHeader, query->length, 01171 offset, "", service->name, ".local", 0)) 01172 { 01173 //PTR query? 01174 if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY) 01175 { 01176 //Format PTR resource record 01177 error = dnsSdAddPtrRecord(interface, response, 01178 service, ttl); 01179 //Any error to report? 01180 if(error) 01181 return error; 01182 01183 //Update the number of shared resource records 01184 response->sharedRecordCount++; 01185 } 01186 } 01187 else if(!mdnsCompareName(query->dnsHeader, query->length, offset, 01188 context->instanceName, service->name, ".local", 0)) 01189 { 01190 //SRV query? 01191 if(qtype == DNS_RR_TYPE_SRV || qtype == DNS_RR_TYPE_ANY) 01192 { 01193 //Format SRV resource record 01194 error = dnsSdAddSrvRecord(interface, response, 01195 service, cacheFlush, ttl); 01196 //Any error to report? 01197 if(error) 01198 return error; 01199 } 01200 01201 //TXT query? 01202 if(qtype == DNS_RR_TYPE_TXT || qtype == DNS_RR_TYPE_ANY) 01203 { 01204 //Format TXT resource record 01205 error = dnsSdAddTxtRecord(interface, response, 01206 service, cacheFlush, ttl); 01207 //Any error to report? 01208 if(error) 01209 return error; 01210 } 01211 01212 //NSEC query? 01213 if(qtype != DNS_RR_TYPE_SRV && qtype != DNS_RR_TYPE_TXT) 01214 { 01215 //Format NSEC resource record 01216 error = dnsSdAddNsecRecord(interface, response, 01217 service, cacheFlush, ttl); 01218 //Any error to report? 01219 if(error) 01220 return error; 01221 } 01222 } 01223 } 01224 } 01225 } 01226 } 01227 01228 //Successful processing 01229 return NO_ERROR; 01230 } 01231 01232 01233 01234 /** 01235 * @brief Parse a resource record from the Authority Section 01236 * @param[in] interface Underlying network interface 01237 * @param[in] query Incoming mDNS query message 01238 * @param[in] offset Offset to first byte of the resource record 01239 * @param[in] record Pointer to the resource record 01240 **/ 01241 01242 void dnsSdParseNsRecord(NetInterface *interface, const MdnsMessage *query, 01243 size_t offset, const DnsResourceRecord *record) 01244 { 01245 uint_t i; 01246 uint16_t rclass; 01247 DnsSdContext *context; 01248 DnsSdService *service; 01249 DnsSrvResourceRecord *srvRecord; 01250 01251 //Point to the DNS-SD context 01252 context = interface->dnsSdContext; 01253 //Make sure DNS-SD has been properly instantiated 01254 if(context == NULL) 01255 return; 01256 01257 //Any services registered? 01258 if(dnsSdGetNumServices(context) > 0) 01259 { 01260 //Loop through the list of registered services 01261 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 01262 { 01263 //Point to the current entry 01264 service = &context->serviceList[i]; 01265 01266 //Valid service? 01267 if(service->name[0] != '\0') 01268 { 01269 //Apply tie-breaking rules 01270 if(!mdnsCompareName(query->dnsHeader, query->length, offset, 01271 context->instanceName, service->name, ".local", 0)) 01272 { 01273 //Convert the class to host byte order 01274 rclass = ntohs(record->rclass); 01275 //Discard Cache Flush flag 01276 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 01277 01278 //Check the class of the resource record 01279 if(rclass == DNS_RR_CLASS_IN) 01280 { 01281 //SRV resource record found? 01282 if(ntohs(record->rtype) == DNS_RR_TYPE_SRV) 01283 { 01284 //Cast resource record 01285 srvRecord = (DnsSrvResourceRecord *) record; 01286 01287 //Compare Priority fields 01288 if(ntohs(srvRecord->priority) > service->priority) 01289 { 01290 context->tieBreakLost = TRUE; 01291 } 01292 else if(ntohs(srvRecord->priority) == service->priority) 01293 { 01294 //Compare Weight fields 01295 if(ntohs(srvRecord->weight) > service->weight) 01296 { 01297 context->tieBreakLost = TRUE; 01298 } 01299 else if(ntohs(srvRecord->weight) == service->weight) 01300 { 01301 //Compare Port fields 01302 if(ntohs(srvRecord->port) > service->port) 01303 { 01304 context->tieBreakLost = TRUE; 01305 } 01306 else if(ntohs(srvRecord->port) == service->port) 01307 { 01308 //Compute the offset of the first byte of the target 01309 offset = srvRecord->target - (uint8_t *) query->dnsHeader; 01310 01311 if(mdnsCompareName(query->dnsHeader, query->length, offset, 01312 context->instanceName, "", ".local", 0) > 0) 01313 { 01314 //The host has lost the tie-break 01315 context->tieBreakLost = TRUE; 01316 } 01317 } 01318 } 01319 } 01320 } 01321 } 01322 } 01323 } 01324 } 01325 } 01326 } 01327 01328 01329 /** 01330 * @brief Parse a resource record from the Answer Section 01331 * @param[in] interface Underlying network interface 01332 * @param[in] response Incoming mDNS response message 01333 * @param[in] offset Offset to first byte of the resource record to be checked 01334 * @param[in] record Pointer to the resource record 01335 **/ 01336 01337 void dnsSdParseAnRecord(NetInterface *interface, const MdnsMessage *response, 01338 size_t offset, const DnsResourceRecord *record) 01339 { 01340 uint_t i; 01341 uint16_t rclass; 01342 DnsSdContext *context; 01343 DnsSdService *service; 01344 01345 //Point to the DNS-SD context 01346 context = interface->dnsSdContext; 01347 //Make sure DNS-SD has been properly instantiated 01348 if(context == NULL) 01349 return; 01350 01351 //Any services registered? 01352 if(dnsSdGetNumServices(context) > 0) 01353 { 01354 //Loop through the list of registered services 01355 for(i = 0; i < DNS_SD_SERVICE_LIST_SIZE; i++) 01356 { 01357 //Point to the current entry 01358 service = &context->serviceList[i]; 01359 01360 //Valid service? 01361 if(service->name[0] != '\0') 01362 { 01363 //Check for conflicts 01364 if(!mdnsCompareName(response->dnsHeader, response->length, offset, 01365 context->instanceName, service->name, ".local", 0)) 01366 { 01367 //Convert the class to host byte order 01368 rclass = ntohs(record->rclass); 01369 //Discard Cache Flush flag 01370 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 01371 01372 //Check the class of the resource record 01373 if(rclass == DNS_RR_CLASS_IN) 01374 { 01375 //SRV resource record found? 01376 if(ntohs(record->rtype) == DNS_RR_TYPE_SRV) 01377 { 01378 //Compute the offset of the first byte of the rdata 01379 offset = record->rdata - (uint8_t *) response->dnsHeader; 01380 01381 //A conflict occurs when a mDNS responder has a unique record for 01382 //which it is currently authoritative, and it receives a mDNS 01383 //response message containing a record with the same name, rrtype 01384 //and rrclass, but inconsistent rdata 01385 if(mdnsCompareName(response->dnsHeader, response->length, offset, 01386 context->instanceName, "", ".local", 0)) 01387 { 01388 //The service instance name is already in use by some other host 01389 context->conflict = TRUE; 01390 } 01391 } 01392 } 01393 } 01394 } 01395 } 01396 } 01397 } 01398 01399 01400 /** 01401 * @brief Additional record generation 01402 * @param[in] interface Underlying network interface 01403 * @param[in,out] response mDNS response message 01404 * @param[in] legacyUnicast This flag is set for legacy unicast responses 01405 **/ 01406 01407 void dnsSdGenerateAdditionalRecords(NetInterface *interface, 01408 MdnsMessage *response, bool_t legacyUnicast) 01409 { 01410 error_t error; 01411 uint_t i; 01412 uint_t j; 01413 size_t n; 01414 size_t offset; 01415 uint_t ancount; 01416 uint16_t rclass; 01417 uint32_t ttl; 01418 bool_t cacheFlush; 01419 DnsSdContext *context; 01420 DnsSdService *service; 01421 DnsResourceRecord *record; 01422 01423 //Point to the DNS-SD context 01424 context = interface->dnsSdContext; 01425 //Make sure DNS-SD has been properly instantiated 01426 if(context == NULL) 01427 return; 01428 01429 //No registered services? 01430 if(dnsSdGetNumServices(context) == 0) 01431 return; 01432 01433 //mDNS responses must not contain any questions in the Question Section 01434 if(response->dnsHeader->qdcount != 0) 01435 return; 01436 01437 //Get the TTL resource record 01438 ttl = context->settings.ttl; 01439 01440 //Check whether the querier originating the query is a simple resolver 01441 if(legacyUnicast) 01442 { 01443 //The resource record TTL given in a legacy unicast response should 01444 //not be greater than ten seconds, even if the true TTL of the mDNS 01445 //resource record is higher 01446 ttl = MIN(ttl, MDNS_LEGACY_UNICAST_RR_TTL); 01447 01448 //The cache-flush bit must not be set in legacy unicast responses 01449 cacheFlush = FALSE; 01450 } 01451 else 01452 { 01453 //The cache-bit should be set for unique resource records 01454 cacheFlush = TRUE; 01455 } 01456 01457 //Point to the first resource record 01458 offset = sizeof(DnsHeader); 01459 01460 //Save the number of resource records in the Answer Section 01461 ancount = response->dnsHeader->ancount; 01462 01463 //Parse the Answer Section 01464 for(i = 0; i < ancount; i++) 01465 { 01466 //Parse resource record name 01467 n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0); 01468 //Invalid name? 01469 if(!n) 01470 break; 01471 01472 //Point to the associated resource record 01473 record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n); 01474 //Point to the resource data 01475 n += sizeof(DnsResourceRecord); 01476 01477 //Make sure the resource record is valid 01478 if(n > response->length) 01479 break; 01480 if((n + ntohs(record->rdlength)) > response->length) 01481 break; 01482 01483 //Convert the record class to host byte order 01484 rclass = ntohs(record->rclass); 01485 //Discard the cache-flush bit 01486 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 01487 01488 //Loop through the list of registered services 01489 for(j = 0; j < DNS_SD_SERVICE_LIST_SIZE; j++) 01490 { 01491 //Point to the current entry 01492 service = &context->serviceList[j]; 01493 01494 //Valid service? 01495 if(service->name[0] != '\0') 01496 { 01497 //Check the class of the resource record 01498 if(rclass == DNS_RR_CLASS_IN) 01499 { 01500 //PTR record? 01501 if(ntohs(record->rtype) == DNS_RR_TYPE_PTR) 01502 { 01503 //Compare service name 01504 if(!mdnsCompareName(response->dnsHeader, response->length, 01505 offset, "", service->name, ".local", 0)) 01506 { 01507 //Format SRV resource record 01508 error = dnsSdAddSrvRecord(interface, 01509 response, service, cacheFlush, ttl); 01510 //Any error to report? 01511 if(error) 01512 return; 01513 01514 //Format TXT resource record 01515 error = dnsSdAddTxtRecord(interface, 01516 response, service, cacheFlush, ttl); 01517 //Any error to report? 01518 if(error) 01519 return; 01520 } 01521 } 01522 //SRV record? 01523 else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV) 01524 { 01525 //Compare service name 01526 if(!mdnsCompareName(response->dnsHeader, response->length, 01527 offset, context->instanceName, service->name, ".local", 0)) 01528 { 01529 //Format TXT resource record 01530 error = dnsSdAddTxtRecord(interface, 01531 response, service, cacheFlush, ttl); 01532 //Any error to report? 01533 if(error) 01534 return; 01535 } 01536 } 01537 } 01538 } 01539 } 01540 01541 //Point to the next resource record 01542 offset = n + ntohs(record->rdlength); 01543 } 01544 01545 //Number of resource records in the Additional Section 01546 response->dnsHeader->arcount += response->dnsHeader->ancount - ancount; 01547 //Number of resource records in the Answer Section 01548 response->dnsHeader->ancount = ancount; 01549 } 01550 01551 01552 /** 01553 * @brief Add PTR record to a mDNS message (in response to a meta-query) 01554 * @param[in] interface Underlying network interface 01555 * @param[in,out] message Pointer to the mDNS message 01556 * @param[in] service Pointer to a DNS-SD service 01557 * @param[in] ttl Resource record TTL (cache lifetime) 01558 * @return Error code 01559 **/ 01560 01561 error_t dnsSdAddServiceEnumPtrRecord(NetInterface *interface, 01562 MdnsMessage *message, const DnsSdService *service, uint32_t ttl) 01563 { 01564 size_t n; 01565 size_t offset; 01566 DnsResourceRecord *record; 01567 01568 //Set the position to the end of the buffer 01569 offset = message->length; 01570 01571 //The first pass calculates the length of the DNS encoded service name 01572 n = mdnsEncodeName("", "_services._dns-sd._udp", ".local", NULL); 01573 01574 //Check the length of the resulting mDNS message 01575 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01576 return ERROR_MESSAGE_TOO_LONG; 01577 01578 //The second pass encodes the service name using the DNS name notation 01579 offset += mdnsEncodeName("", "_services._dns-sd._udp", 01580 ".local", (uint8_t *) message->dnsHeader + offset); 01581 01582 //Consider the length of the resource record itself 01583 if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) 01584 return ERROR_MESSAGE_TOO_LONG; 01585 01586 //Point to the corresponding resource record 01587 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 01588 01589 //Fill in resource record 01590 record->rtype = HTONS(DNS_RR_TYPE_PTR); 01591 record->rclass = HTONS(DNS_RR_CLASS_IN); 01592 record->ttl = htonl(ttl); 01593 01594 //Advance write index 01595 offset += sizeof(DnsResourceRecord); 01596 01597 //The first pass calculates the length of the DNS encoded service name 01598 n = mdnsEncodeName("", service->name, ".local", NULL); 01599 01600 //Check the length of the resulting mDNS message 01601 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01602 return ERROR_MESSAGE_TOO_LONG; 01603 01604 //The second pass encodes the service name using DNS notation 01605 n = mdnsEncodeName("", service->name, 01606 ".local", record->rdata); 01607 01608 //Convert length field to network byte order 01609 record->rdlength = htons(n); 01610 01611 //Number of resource records in the answer section 01612 message->dnsHeader->ancount++; 01613 //Update the length of the DNS message 01614 message->length = offset + n; 01615 01616 //Successful processing 01617 return NO_ERROR; 01618 } 01619 01620 01621 /** 01622 * @brief Add PTR record to a mDNS message 01623 * @param[in] interface Underlying network interface 01624 * @param[in,out] message Pointer to the mDNS message 01625 * @param[in] service Pointer to a DNS-SD service 01626 * @param[in] ttl Resource record TTL (cache lifetime) 01627 * @return Error code 01628 **/ 01629 01630 error_t dnsSdAddPtrRecord(NetInterface *interface, 01631 MdnsMessage *message, const DnsSdService *service, uint32_t ttl) 01632 { 01633 size_t n; 01634 size_t offset; 01635 bool_t duplicate; 01636 DnsSdContext *context; 01637 DnsResourceRecord *record; 01638 01639 //Point to the DNS-SD context 01640 context = interface->dnsSdContext; 01641 01642 //Check whether the resource record is already present in the Answer 01643 //Section of the message 01644 duplicate = mdnsCheckDuplicateRecord(message, "", 01645 service->name, ".local", DNS_RR_TYPE_PTR); 01646 01647 //The duplicates should be suppressed and the resource record should 01648 //appear only once in the list 01649 if(!duplicate) 01650 { 01651 //Set the position to the end of the buffer 01652 offset = message->length; 01653 01654 //The first pass calculates the length of the DNS encoded service name 01655 n = mdnsEncodeName("", service->name, ".local", NULL); 01656 01657 //Check the length of the resulting mDNS message 01658 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01659 return ERROR_MESSAGE_TOO_LONG; 01660 01661 //Encode the service name using the DNS name notation 01662 offset += mdnsEncodeName("", service->name, 01663 ".local", (uint8_t *) message->dnsHeader + offset); 01664 01665 //Consider the length of the resource record itself 01666 if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) 01667 return ERROR_MESSAGE_TOO_LONG; 01668 01669 //Point to the corresponding resource record 01670 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 01671 01672 //Fill in resource record 01673 record->rtype = HTONS(DNS_RR_TYPE_PTR); 01674 record->rclass = HTONS(DNS_RR_CLASS_IN); 01675 record->ttl = htonl(ttl); 01676 01677 //Advance write index 01678 offset += sizeof(DnsResourceRecord); 01679 01680 //The first pass calculates the length of the DNS encoded instance name 01681 n = mdnsEncodeName(context->instanceName, service->name, ".local", NULL); 01682 01683 //Check the length of the resulting mDNS message 01684 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01685 return ERROR_MESSAGE_TOO_LONG; 01686 01687 //The second pass encodes the instance name using DNS notation 01688 n = mdnsEncodeName(context->instanceName, 01689 service->name, ".local", record->rdata); 01690 01691 //Convert length field to network byte order 01692 record->rdlength = htons(n); 01693 01694 //Number of resource records in the answer section 01695 message->dnsHeader->ancount++; 01696 //Update the length of the DNS message 01697 message->length = offset + n; 01698 } 01699 01700 //Successful processing 01701 return NO_ERROR; 01702 } 01703 01704 01705 /** 01706 * @brief Add SRV record to a mDNS message 01707 * @param[in] interface Underlying network interface 01708 * @param[in,out] message Pointer to the mDNS message 01709 * @param[in] service Pointer to a DNS-SD service 01710 * @param[in] cacheFlush Cache-flush bit 01711 * @param[in] ttl Resource record TTL (cache lifetime) 01712 * @return Error code 01713 **/ 01714 01715 error_t dnsSdAddSrvRecord(NetInterface *interface, MdnsMessage *message, 01716 const DnsSdService *service, bool_t cacheFlush, uint32_t ttl) 01717 { 01718 size_t n; 01719 size_t offset; 01720 bool_t duplicate; 01721 MdnsResponderContext *mdnsResponderContext; 01722 DnsSdContext *dnsSdContext; 01723 DnsSrvResourceRecord *record; 01724 01725 //Point to the mDNS responder context 01726 mdnsResponderContext = interface->mdnsResponderContext; 01727 //Point to the DNS-SD context 01728 dnsSdContext = interface->dnsSdContext; 01729 01730 //Check whether the resource record is already present in the Answer 01731 //Section of the message 01732 duplicate = mdnsCheckDuplicateRecord(message, dnsSdContext->instanceName, 01733 service->name, ".local", DNS_RR_TYPE_SRV); 01734 01735 //The duplicates should be suppressed and the resource record should 01736 //appear only once in the list 01737 if(!duplicate) 01738 { 01739 //Set the position to the end of the buffer 01740 offset = message->length; 01741 01742 //The first pass calculates the length of the DNS encoded instance name 01743 n = mdnsEncodeName(dnsSdContext->instanceName, 01744 service->name, ".local", NULL); 01745 01746 //Check the length of the resulting mDNS message 01747 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01748 return ERROR_MESSAGE_TOO_LONG; 01749 01750 //The second pass encodes the instance name using DNS notation 01751 offset += mdnsEncodeName(dnsSdContext->instanceName, 01752 service->name, ".local", (uint8_t *) message->dnsHeader + offset); 01753 01754 //Consider the length of the resource record itself 01755 if((offset + sizeof(DnsSrvResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) 01756 return ERROR_MESSAGE_TOO_LONG; 01757 01758 //Point to the corresponding resource record 01759 record = (DnsSrvResourceRecord *) DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 01760 01761 //Fill in resource record 01762 record->rtype = HTONS(DNS_RR_TYPE_SRV); 01763 record->rclass = HTONS(DNS_RR_CLASS_IN); 01764 record->ttl = htonl(ttl); 01765 record->priority = htons(service->priority); 01766 record->weight = htons(service->weight); 01767 record->port = htons(service->port); 01768 01769 //Check whether the cache-flush bit should be set 01770 if(cacheFlush) 01771 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 01772 01773 //Advance write index 01774 offset += sizeof(DnsSrvResourceRecord); 01775 01776 //The first pass calculates the length of the DNS encoded target name 01777 n = mdnsEncodeName("", mdnsResponderContext->hostname, 01778 ".local", NULL); 01779 01780 //Check the length of the resulting mDNS message 01781 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01782 return ERROR_MESSAGE_TOO_LONG; 01783 01784 //The second pass encodes the target name using DNS notation 01785 n = mdnsEncodeName("", mdnsResponderContext->hostname, 01786 ".local", record->target); 01787 01788 //Calculate data length 01789 record->rdlength = htons(sizeof(DnsSrvResourceRecord) - 01790 sizeof(DnsResourceRecord) + n); 01791 01792 //Number of resource records in the answer section 01793 message->dnsHeader->ancount++; 01794 //Update the length of the DNS message 01795 message->length = offset + n; 01796 } 01797 01798 //Successful processing 01799 return NO_ERROR; 01800 } 01801 01802 01803 /** 01804 * @brief Add TXT record to a mDNS message 01805 * @param[in] interface Underlying network interface 01806 * @param[in,out] message Pointer to the mDNS message 01807 * @param[in] service Pointer to a DNS-SD service 01808 * @param[in] cacheFlush Cache-flush bit 01809 * @param[in] ttl Resource record TTL (cache lifetime) 01810 * @return Error code 01811 **/ 01812 01813 error_t dnsSdAddTxtRecord(NetInterface *interface, MdnsMessage *message, 01814 const DnsSdService *service, bool_t cacheFlush, uint32_t ttl) 01815 { 01816 size_t n; 01817 size_t offset; 01818 bool_t duplicate; 01819 DnsSdContext *context; 01820 DnsResourceRecord *record; 01821 01822 //Point to the DNS-SD context 01823 context = interface->dnsSdContext; 01824 01825 //Check whether the resource record is already present in the Answer 01826 //Section of the message 01827 duplicate = mdnsCheckDuplicateRecord(message, context->instanceName, 01828 service->name, ".local", DNS_RR_TYPE_TXT); 01829 01830 //The duplicates should be suppressed and the resource record should 01831 //appear only once in the list 01832 if(!duplicate) 01833 { 01834 //Set the position to the end of the buffer 01835 offset = message->length; 01836 01837 //The first pass calculates the length of the DNS encoded instance name 01838 n = mdnsEncodeName(context->instanceName, service->name, ".local", NULL); 01839 01840 //Check the length of the resulting mDNS message 01841 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01842 return ERROR_MESSAGE_TOO_LONG; 01843 01844 //The second pass encodes the instance name using DNS notation 01845 offset += mdnsEncodeName(context->instanceName, 01846 service->name, ".local", (uint8_t *) message->dnsHeader + offset); 01847 01848 //Consider the length of the resource record itself 01849 if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) 01850 return ERROR_MESSAGE_TOO_LONG; 01851 01852 //Point to the corresponding resource record 01853 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 01854 01855 //Fill in resource record 01856 record->rtype = HTONS(DNS_RR_TYPE_TXT); 01857 record->rclass = HTONS(DNS_RR_CLASS_IN); 01858 record->ttl = htonl(ttl); 01859 record->rdlength = htons(service->metadataLength); 01860 01861 //Check whether the cache-flush bit should be set 01862 if(cacheFlush) 01863 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 01864 01865 //Advance write index 01866 offset += sizeof(DnsResourceRecord); 01867 01868 //Check the length of the resulting mDNS message 01869 if((offset + service->metadataLength) > MDNS_MESSAGE_MAX_SIZE) 01870 return ERROR_MESSAGE_TOO_LONG; 01871 01872 //Copy metadata 01873 memcpy(record->rdata, service->metadata, service->metadataLength); 01874 01875 //Update the length of the DNS message 01876 message->length = offset + service->metadataLength; 01877 //Number of resource records in the answer section 01878 message->dnsHeader->ancount++; 01879 } 01880 01881 //Successful processing 01882 return NO_ERROR; 01883 } 01884 01885 01886 /** 01887 * @brief Add NSEC record to a mDNS message 01888 * @param[in] interface Underlying network interface 01889 * @param[in,out] message Pointer to the mDNS message 01890 * @param[in] service Pointer to a DNS-SD service 01891 * @param[in] cacheFlush Cache-flush bit 01892 * @param[in] ttl Resource record TTL (cache lifetime) 01893 * @return Error code 01894 **/ 01895 01896 error_t dnsSdAddNsecRecord(NetInterface *interface, MdnsMessage *message, 01897 const DnsSdService *service, bool_t cacheFlush, uint32_t ttl) 01898 { 01899 size_t n; 01900 size_t offset; 01901 bool_t duplicate; 01902 size_t bitmapLength; 01903 uint8_t bitmap[8]; 01904 DnsSdContext *context; 01905 DnsResourceRecord *record; 01906 01907 //Point to the DNS-SD context 01908 context = interface->dnsSdContext; 01909 01910 //Check whether the resource record is already present in the Answer 01911 //Section of the message 01912 duplicate = mdnsCheckDuplicateRecord(message, context->instanceName, 01913 service->name, ".local", DNS_RR_TYPE_NSEC); 01914 01915 //The duplicates should be suppressed and the resource record should 01916 //appear only once in the list 01917 if(!duplicate) 01918 { 01919 //The bitmap identifies the resource record types that exist 01920 memset(bitmap, 0, sizeof(bitmap)); 01921 01922 //TXT resource record is supported 01923 DNS_SET_NSEC_BITMAP(bitmap, DNS_RR_TYPE_TXT); 01924 //SRV resource record is supported 01925 DNS_SET_NSEC_BITMAP(bitmap, DNS_RR_TYPE_SRV); 01926 01927 //Compute the length of the bitmap 01928 for(bitmapLength = sizeof(bitmap); bitmapLength > 0; bitmapLength--) 01929 { 01930 //Trailing zero octets in the bitmap must be omitted... 01931 if(bitmap[bitmapLength - 1] != 0x00) 01932 break; 01933 } 01934 01935 //Set the position to the end of the buffer 01936 offset = message->length; 01937 01938 //The first pass calculates the length of the DNS encoded instance name 01939 n = mdnsEncodeName(context->instanceName, service->name, ".local", NULL); 01940 01941 //Check the length of the resulting mDNS message 01942 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01943 return ERROR_MESSAGE_TOO_LONG; 01944 01945 //The second pass encodes the instance name using the DNS name notation 01946 offset += mdnsEncodeName(context->instanceName, service->name, 01947 ".local", (uint8_t *) message->dnsHeader + offset); 01948 01949 //Consider the length of the resource record itself 01950 if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) 01951 return ERROR_MESSAGE_TOO_LONG; 01952 01953 //Point to the corresponding resource record 01954 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 01955 01956 //Fill in resource record 01957 record->rtype = HTONS(DNS_RR_TYPE_NSEC); 01958 record->rclass = HTONS(DNS_RR_CLASS_IN); 01959 record->ttl = htonl(ttl); 01960 01961 //Check whether the cache-flush bit should be set 01962 if(cacheFlush) 01963 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 01964 01965 //Advance write index 01966 offset += sizeof(DnsResourceRecord); 01967 01968 //Check the length of the resulting mDNS message 01969 if((offset + n + 2) > MDNS_MESSAGE_MAX_SIZE) 01970 return ERROR_MESSAGE_TOO_LONG; 01971 01972 //The Next Domain Name field contains the record's own name 01973 mdnsEncodeName(context->instanceName, service->name, 01974 ".local", record->rdata); 01975 01976 //DNS NSEC record is limited to Window Block number zero 01977 record->rdata[n++] = 0; 01978 //The Bitmap Length is a value in the range 1-32 01979 record->rdata[n++] = bitmapLength; 01980 01981 //The Bitmap data identifies the resource record types that exist 01982 memcpy(record->rdata + n, bitmap, bitmapLength); 01983 01984 //Convert length field to network byte order 01985 record->rdlength = htons(n + bitmapLength); 01986 01987 //Number of resource records in the answer section 01988 message->dnsHeader->ancount++; 01989 //Update the length of the DNS message 01990 message->length = offset + n + bitmapLength; 01991 } 01992 01993 //Successful processing 01994 return NO_ERROR; 01995 } 01996 01997 #endif 01998
Generated on Tue Jul 12 2022 17:10:13 by
