Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dns_sd.c Source File

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