Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mdns_client.c Source File

mdns_client.c

Go to the documentation of this file.
00001 /**
00002  * @file mdns_client.c
00003  * @brief mDNS client (Multicast DNS)
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL MDNS_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "ipv6/ipv6.h"
00035 #include "ipv6/ipv6_misc.h"
00036 #include "mdns/mdns_client.h"
00037 #include "mdns/mdns_responder.h"
00038 #include "mdns/mdns_common.h"
00039 #include "dns/dns_debug.h"
00040 #include "debug.h"
00041 
00042 //Check TCP/IP stack configuration
00043 #if (MDNS_CLIENT_SUPPORT == ENABLED)
00044 
00045 
00046 /**
00047  * @brief Resolve a host name using mDNS
00048  * @param[in] interface Underlying network interface
00049  * @param[in] name Name of the host to be resolved
00050  * @param[in] type Host type (IPv4 or IPv6)
00051  * @param[out] ipAddr IP address corresponding to the specified host name
00052  **/
00053 
00054 error_t mdnsClientResolve(NetInterface *interface,
00055    const char_t *name, HostType type, IpAddr *ipAddr)
00056 {
00057    error_t error;
00058    DnsCacheEntry *entry;
00059 
00060 #if (NET_RTOS_SUPPORT == ENABLED)
00061    systime_t delay;
00062 
00063    //Debug message
00064    TRACE_INFO("Resolving host name %s (mDNS resolver)...\r\n", name);
00065 #endif
00066 
00067    //Get exclusive access
00068    osAcquireMutex(&netMutex);
00069 
00070    //Search the DNS cache for the specified host name
00071    entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_MDNS);
00072 
00073    //Check whether a matching entry has been found
00074    if(entry)
00075    {
00076       //Host name already resolved?
00077       if(entry->state == DNS_STATE_RESOLVED ||
00078          entry->state == DNS_STATE_PERMANENT)
00079       {
00080          //Return the corresponding IP address
00081          *ipAddr = entry->ipAddr;
00082          //Successful host name resolution
00083          error = NO_ERROR;
00084       }
00085       else
00086       {
00087          //Host name resolution is in progress...
00088          error = ERROR_IN_PROGRESS;
00089       }
00090    }
00091    else
00092    {
00093       //If no entry exists, then create a new one
00094       entry = dnsCreateEntry();
00095 
00096       //Record the host name whose IP address is unknown
00097       strcpy(entry->name, name);
00098 
00099       //Initialize DNS cache entry
00100       entry->type = type;
00101       entry->protocol = HOST_NAME_RESOLVER_MDNS;
00102       entry->interface = interface;
00103 
00104       //Initialize retransmission counter
00105       entry->retransmitCount = MDNS_CLIENT_MAX_RETRIES;
00106       //Send mDNS query
00107       error = mdnsClientSendQuery(entry);
00108 
00109       //mDNS message successfully sent?
00110       if(!error)
00111       {
00112          //Save the time at which the query message was sent
00113          entry->timestamp = osGetSystemTime();
00114          //Set timeout value
00115          entry->timeout = MDNS_CLIENT_INIT_TIMEOUT;
00116          entry->maxTimeout = MDNS_CLIENT_MAX_TIMEOUT;
00117          //Decrement retransmission counter
00118          entry->retransmitCount--;
00119 
00120          //Switch state
00121          entry->state = DNS_STATE_IN_PROGRESS;
00122          //Host name resolution is in progress
00123          error = ERROR_IN_PROGRESS;
00124       }
00125    }
00126 
00127    //Release exclusive access
00128    osReleaseMutex(&netMutex);
00129 
00130 #if (NET_RTOS_SUPPORT == ENABLED)
00131    //Set default polling interval
00132    delay = DNS_CACHE_INIT_POLLING_INTERVAL;
00133 
00134    //Wait the host name resolution to complete
00135    while(error == ERROR_IN_PROGRESS)
00136    {
00137       //Wait until the next polling period
00138       osDelayTask(delay);
00139 
00140       //Get exclusive access
00141       osAcquireMutex(&netMutex);
00142 
00143       //Search the DNS cache for the specified host name
00144       entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_MDNS);
00145 
00146       //Check whether a matching entry has been found
00147       if(entry)
00148       {
00149          //Host name successfully resolved?
00150          if(entry->state == DNS_STATE_RESOLVED)
00151          {
00152             //Return the corresponding IP address
00153             *ipAddr = entry->ipAddr;
00154             //Successful host name resolution
00155             error = NO_ERROR;
00156          }
00157       }
00158       else
00159       {
00160          //Host name resolution failed
00161          error = ERROR_FAILURE;
00162       }
00163 
00164       //Release exclusive access
00165       osReleaseMutex(&netMutex);
00166 
00167       //Backoff support for less aggressive polling
00168       delay = MIN(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL);
00169    }
00170 
00171    //Check status code
00172    if(error)
00173    {
00174       //Failed to resolve host name
00175       TRACE_INFO("Host name resolution failed!\r\n");
00176    }
00177    else
00178    {
00179       //Successful host name resolution
00180       TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL));
00181    }
00182 #endif
00183 
00184    //Return status code
00185    return error;
00186 }
00187 
00188 
00189 /**
00190  * @brief Send a mDNS query message
00191  * @param[in] entry Pointer to a valid DNS cache entry
00192  * @return Error code
00193  **/
00194 
00195 error_t mdnsClientSendQuery(DnsCacheEntry *entry)
00196 {
00197    error_t error;
00198    DnsQuestion *dnsQuestion;
00199    MdnsMessage message;
00200 
00201    //Create an empty mDNS query message
00202    error = mdnsCreateMessage(&message, FALSE);
00203    //Any error to report?
00204    if(error)
00205       return error;
00206 
00207    //Encode the host name using the DNS name notation
00208    message.length += dnsEncodeName(entry->name, message.dnsHeader->questions);
00209 
00210    //Point to the corresponding question structure
00211    dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length);
00212 
00213 #if (IPV4_SUPPORT == ENABLED)
00214    //An IPv4 address is expected?
00215    if(entry->type == HOST_TYPE_IPV4)
00216    {
00217       //Fill in question structure
00218       dnsQuestion->qtype = HTONS(DNS_RR_TYPE_A);
00219       dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
00220    }
00221 #endif
00222 #if (IPV6_SUPPORT == ENABLED)
00223    //An IPv6 address is expected?
00224    if(entry->type == HOST_TYPE_IPV6)
00225    {
00226       //Fill in question structure
00227       dnsQuestion->qtype = HTONS(DNS_RR_TYPE_AAAA);
00228       dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
00229    }
00230 #endif
00231 
00232    //Update the length of the mDNS query message
00233    message.length += sizeof(DnsQuestion);
00234    //Number of questions in the Question Section
00235    message.dnsHeader->qdcount = 1;
00236 
00237    //Send mDNS message
00238    error = mdnsSendMessage(entry->interface, &message, NULL, MDNS_PORT);
00239 
00240    //Free previously allocated memory
00241    mdnsDeleteMessage(&message);
00242 
00243    //Return status code
00244    return error;
00245 }
00246 
00247 
00248 /**
00249  * @brief Parse a resource record from the Answer Section
00250  * @param[in] interface Underlying network interface
00251  * @param[in] message Pointer to the mDNS message
00252  * @param[in] offset Offset to first byte of the resource record
00253  * @param[in] record Pointer to the resource record
00254  **/
00255 
00256 void mdnsClientParseAnRecord(NetInterface *interface,
00257    const MdnsMessage *message, size_t offset, const DnsResourceRecord *record)
00258 {
00259    uint_t i;
00260    uint16_t rclass;
00261    DnsCacheEntry *entry;
00262 
00263    //Loop through DNS cache entries
00264    for(i = 0; i < DNS_CACHE_SIZE; i++)
00265    {
00266       //Point to the current entry
00267       entry = &dnsCache[i];
00268 
00269       //mDNS name resolution in progress?
00270       if(entry->state == DNS_STATE_IN_PROGRESS &&
00271          entry->protocol == HOST_NAME_RESOLVER_MDNS)
00272       {
00273          //Compare resource record name
00274          if(!dnsCompareName(message->dnsHeader, message->length, offset, entry->name, 0))
00275          {
00276             //Convert the class to host byte order
00277             rclass = ntohs(record->rclass);
00278             //Discard Cache Flush flag
00279             rclass &= ~MDNS_RCLASS_CACHE_FLUSH;
00280 
00281             //Check the class of the resource record
00282             if(rclass == DNS_RR_CLASS_IN)
00283             {
00284 #if (IPV4_SUPPORT == ENABLED)
00285                //IPv4 address expected?
00286                if(entry->type == HOST_TYPE_IPV4)
00287                {
00288                   //A resource record found?
00289                   if(ntohs(record->rtype) == DNS_RR_TYPE_A)
00290                   {
00291                      //Verify the length of the data field
00292                      if(ntohs(record->rdlength) == sizeof(Ipv4Addr))
00293                      {
00294                         //Copy the IPv4 address
00295                         entry->ipAddr.length = sizeof(Ipv4Addr);
00296                         ipv4CopyAddr(&entry->ipAddr.ipv4Addr, record->rdata);
00297 
00298                         //Save current time
00299                         entry->timestamp = osGetSystemTime();
00300                         //Save TTL value
00301                         entry->timeout = ntohl(record->ttl) * 1000;
00302                         //Limit the lifetime of the mDNS cache entries
00303                         entry->timeout = MIN(entry->timeout, MDNS_MAX_LIFETIME);
00304 
00305                         //Host name successfully resolved
00306                         entry->state = DNS_STATE_RESOLVED;
00307                      }
00308                   }
00309                }
00310 #endif
00311 #if (IPV6_SUPPORT == ENABLED)
00312                //IPv6 address expected?
00313                if(entry->type == HOST_TYPE_IPV6)
00314                {
00315                   //AAAA resource record found?
00316                   if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
00317                   {
00318                      //Verify the length of the data field
00319                      if(ntohs(record->rdlength) == sizeof(Ipv6Addr))
00320                      {
00321                         //Copy the IPv6 address
00322                         entry->ipAddr.length = sizeof(Ipv6Addr);
00323                         ipv6CopyAddr(&entry->ipAddr.ipv6Addr, record->rdata);
00324 
00325                         //Save current time
00326                         entry->timestamp = osGetSystemTime();
00327                         //Save TTL value
00328                         entry->timeout = ntohl(record->ttl) * 1000;
00329                         //Limit the lifetime of the mDNS cache entries
00330                         entry->timeout = MIN(entry->timeout, MDNS_MAX_LIFETIME);
00331 
00332                         //Host name successfully resolved
00333                         entry->state = DNS_STATE_RESOLVED;
00334                      }
00335                   }
00336                }
00337 #endif
00338             }
00339          }
00340       }
00341    }
00342 }
00343 
00344 #endif
00345