Ejemplo n.º 1
0
error_t dnsResolve(NetInterface *interface, const char_t *name, IpAddr *ipAddr)
{
   error_t error;
   uint_t i;
   size_t length;
   uint16_t identifier;
   IpAddr serverIpAddr;
   Socket *socket;
   DnsHeader *dnsMessage;

   //Debug message
   TRACE_INFO("Trying to resolve %s...\r\n", name);

   //Use default network interface?
   if(!interface)
      interface = tcpIpStackGetDefaultInterface();

   //Allocate a memory buffer to hold DNS messages
   dnsMessage = memPoolAlloc(DNS_MESSAGE_MAX_SIZE);
   //Failed to allocate memory?
   if(!dnsMessage)
      return ERROR_OUT_OF_MEMORY;

   //Open a UDP socket
   socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_PROTOCOL_UDP);

   //Failed to open socket?
   if(!socket)
   {
      //Free previously allocated memory
      osMemFree(dnsMessage);
      //Return status code
      return ERROR_OPEN_FAILED;
   }

#if (IPV4_SUPPORT == ENABLED)
   //IP address of the DNS server
   serverIpAddr.length = sizeof(Ipv4Addr);
   serverIpAddr.ipv4Addr = interface->ipv4Config.dnsServer[0];
#elif (IPV6_SUPPORT == ENABLED)
   //IP address of the DNS server
   serverIpAddr.length = sizeof(Ipv6Addr);
   serverIpAddr.ipv6Addr = interface->ipv6Config.dnsServer[0];
#endif

   //Associate the socket with the relevant interface
   error = socketBindToInterface(socket, interface);

   //Any error to report?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(dnsMessage);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Connect the newly created socket to the primary DNS server
   error = socketConnect(socket, &serverIpAddr, DNS_PORT);

   //Failed to connect?
   if(error)
   {
      //Free previously allocated memory
      osMemFree(dnsMessage);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //An identifier is used by the client to match replies
   //with corresponding requests
   identifier = rand();

   //Try to retransmit the DNS message if the previous query timed out
   for(i = 0; i < DNS_MAX_RETRIES; i++)
   {
      //Send DNS query message
      error = dnsSendQuery(socket, dnsMessage, identifier, name);
      //Failed to send message ?
      if(error) break;

      //Adjust receive timeout
      error = socketSetTimeout(socket, DNS_REQUEST_TIMEOUT);
      //Any error to report?
      if(error) break;

      //Wait for the server response
      error = socketReceive(socket, dnsMessage, DNS_MESSAGE_MAX_SIZE, &length, 0);

      //Any response from the specified DNS server?
      if(!error)
      {
         //Parse DNS response
         error = dnsParseResponse(dnsMessage, length, identifier, ipAddr);
         //DNS response successfully decoded?
         if(!error) break;
      }
   }

   //The maximum number of retransmissions has been reached?
   if(i >= DNS_MAX_RETRIES)
      error = ERROR_TIMEOUT;

   //Free previously allocated memory
   osMemFree(dnsMessage);
   //Close socket
   socketClose(socket);

   //Debug message
   if(!error)
   {
      //Name resolution succeeds
      TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL));
   }
   else
   {
      //Report an error
      TRACE_ERROR("DNS resolution failed!\r\n");
   }

   //Return status code
   return error;
}
Ejemplo n.º 2
0
void dnsTick(void)
{
   error_t error;
   uint_t i;
   systime_t time;
   DnsCacheEntry *entry;

   //Get current time
   time = osGetSystemTime();

   //Acquire exclusive access to the DNS cache
   osAcquireMutex(&dnsCacheMutex);

   //Go through DNS cache
   for(i = 0; i < DNS_CACHE_SIZE; i++)
   {
      //Point to the current entry
      entry = &dnsCache[i];

      //Name resolution in progress?
      if(entry->state == DNS_STATE_IN_PROGRESS)
      {
         //The request timed out?
         if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
         {
            //Check whether the maximum number of retransmissions has been exceeded
            if(entry->retransmitCount > 0)
            {
#if (DNS_CLIENT_SUPPORT == ENABLED)
               //DNS resolver?
               if(entry->protocol == HOST_NAME_RESOLVER_DNS)
               {
                  //Retransmit DNS query
                  error = dnsSendQuery(entry);
               }
               else
#endif
#if (MDNS_CLIENT_SUPPORT == ENABLED)
               //mDNS resolver?
               if(entry->protocol == HOST_NAME_RESOLVER_MDNS)
               {
                  //Retransmit mDNS query
                  error = mdnsSendQuery(entry);
               }
               else
#endif
#if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
               //NetBIOS Name Service resolver?
               if(entry->protocol == HOST_NAME_RESOLVER_NBNS)
               {
                  //Retransmit NBNS query
                  error = nbnsSendQuery(entry);
               }
               else
#endif
               //Unknown protocol?
               {
                  error = ERROR_FAILURE;
               }

               //Query message successfully sent?
               if(!error)
               {
                  //Save the time at which the query message was sent
                  entry->timestamp = time;
                  //The timeout value is doubled for each subsequent retransmission
                  entry->timeout = MIN(entry->timeout * 2, entry->maxTimeout);
                  //Decrement retransmission counter
                  entry->retransmitCount--;
               }
               else
               {
                  //The entry should be deleted since name resolution has failed
                  dnsDeleteEntry(entry);
               }
            }
#if (DNS_CLIENT_SUPPORT == ENABLED)
            //DNS resolver?
            else if(entry->protocol == HOST_NAME_RESOLVER_DNS)
            {
               //Select the next DNS server
               entry->dnsServerNum++;
               //Initialize retransmission counter
               entry->retransmitCount = DNS_CLIENT_MAX_RETRIES;
               //Send DNS query
               error = dnsSendQuery(entry);

               //DNS message successfully sent?
               if(!error)
               {
                  //Save the time at which the query message was sent
                  entry->timestamp = time;
                  //Set timeout value
                  entry->timeout = DNS_CLIENT_INIT_TIMEOUT;
                  //Decrement retransmission counter
                  entry->retransmitCount--;
               }
               else
               {
                  //The entry should be deleted since name resolution has failed
                  dnsDeleteEntry(entry);
               }
            }
#endif
            else
            {
               //The maximum number of retransmissions has been exceeded
               dnsDeleteEntry(entry);
            }
         }
      }
      //Name successfully resolved?
      else if(entry->state == DNS_STATE_RESOLVED)
      {
         //Check the lifetime of the current DNS cache entry
         if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
         {
            //Periodically time out DNS cache entries
            dnsDeleteEntry(entry);
         }
      }
   }

   //Release exclusive access to the DNS cache
   osReleaseMutex(&dnsCacheMutex);
}
Ejemplo n.º 3
0
error_t dnsResolve(NetInterface *interface,
   const char_t *name, HostType type, IpAddr *ipAddr)
{
   error_t error;
   systime_t delay;
   DnsCacheEntry *entry;

   //Debug message
   TRACE_INFO("Resolving host name %s (DNS resolver)...\r\n", name);

   //Acquire exclusive access to the DNS cache
   osMutexAcquire(dnsCacheMutex);

   //Search the DNS cache for the specified host name
   entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS);

   //Check whether a matching entry has been found
   if(entry)
   {
      //Host name already resolved?
      if(entry->state == DNS_STATE_RESOLVED ||
         entry->state == DNS_STATE_PERMANENT)
      {
         //Return the corresponding IP address
         *ipAddr = entry->ipAddr;
         //Successful host name resolution
         error = NO_ERROR;
      }
      else
      {
         //Host name resolution is in progress...
         error = ERROR_IN_PROGRESS;
      }
   }
   else
   {
      //If no entry exists, then create a new one
      entry = dnsCreateEntry();

      //Record the host name whose IP address is unknown
      strcpy(entry->name, name);

      //Initialize DNS cache entry
      entry->type = type;
      entry->protocol = HOST_NAME_RESOLVER_DNS;
      entry->interface = interface;
      //Select primary DNS server
      entry->dnsServerNum = 0;
      //Get an ephemeral port number
      entry->port = socketGetEphemeralPort();

      //An identifier is used by the DNS client to match replies
      //with corresponding requests
      entry->id = tcpIpStackGetRand();

      //Callback function to be called when a DNS response is received
      error = udpAttachRxCallback(interface, entry->port, dnsProcessResponse, NULL);

      //Check status code
      if(!error)
      {
         //Initialize retransmission counter
         entry->retransmitCount = DNS_CLIENT_MAX_RETRIES;
         //Send DNS query
         error = dnsSendQuery(entry);

         //DNS message successfully sent?
         if(!error)
         {
            //Save the time at which the query message was sent
            entry->timestamp = osGetTickCount();
            //Set timeout value
            entry->timeout = DNS_CLIENT_INIT_TIMEOUT;
            entry->maxTimeout = DNS_CLIENT_MAX_TIMEOUT;
            //Decrement retransmission counter
            entry->retransmitCount--;

            //Switch state
            entry->state = DNS_STATE_IN_PROGRESS;
            //Host name resolution is in progress
            error = ERROR_IN_PROGRESS;
         }
         else
         {
            //Unregister callback function
            udpDetachRxCallback(interface, entry->port);
         }
      }
   }

   //Release exclusive access to the DNS cache
   osMutexRelease(dnsCacheMutex);

   //Set default polling interval
   delay = DNS_CACHE_INIT_POLLING_INTERVAL;

   //Wait the host name resolution to complete
   while(error == ERROR_IN_PROGRESS)
   {
      //Wait until the next polling period
      osDelay(delay);

      //Acquire exclusive access to the DNS cache
      osMutexAcquire(dnsCacheMutex);

      //Search the DNS cache for the specified host name
      entry = dnsFindEntry(interface, name, type, HOST_NAME_RESOLVER_DNS);

      //Check whether a matching entry has been found
      if(entry)
      {
         //Host name successfully resolved?
         if(entry->state == DNS_STATE_RESOLVED)
         {
            //Return the corresponding IP address
            *ipAddr = entry->ipAddr;
            //Successful host name resolution
            error = NO_ERROR;
         }
      }
      else
      {
         //Host name resolution failed
         error = ERROR_FAILURE;
      }

      //Release exclusive access to the DNS cache
      osMutexRelease(dnsCacheMutex);

      //Backoff support for less aggressive polling
      delay = min(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL);
   }

   //Check status code
   if(error)
   {
      //Failed to resolve host name
      TRACE_INFO("Host name resolution failed!\r\n");
   }
   else
   {
      //Successful host name resolution
      TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL));
   }

   //Return status code
   return error;
}