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; }
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); }
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; }