Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nbns_client.c Source File

nbns_client.c

Go to the documentation of this file.
00001 /**
00002  * @file nbns_client.c
00003  * @brief NBNS client (NetBIOS Name Service)
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 NBNS_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "netbios/nbns_client.h"
00035 #include "netbios/nbns_common.h"
00036 #include "dns/dns_debug.h"
00037 #include "debug.h"
00038 
00039 //Check TCP/IP stack configuration
00040 #if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
00041 
00042 
00043 /**
00044  * @brief Resolve a host name using NBNS
00045  * @param[in] interface Underlying network interface
00046  * @param[in] name Name of the host to be resolved
00047  * @param[out] ipAddr IP address corresponding to the specified host name
00048  **/
00049 
00050 error_t nbnsResolve(NetInterface *interface, const char_t *name, IpAddr *ipAddr)
00051 {
00052    error_t error;
00053    DnsCacheEntry *entry;
00054 
00055 #if (NET_RTOS_SUPPORT == ENABLED)
00056    systime_t delay;
00057 
00058    //Debug message
00059    TRACE_INFO("Resolving host name %s (NBNS resolver)...\r\n", name);
00060 #endif
00061 
00062    //Get exclusive access
00063    osAcquireMutex(&netMutex);
00064 
00065    //Search the DNS cache for the specified host name
00066    entry = dnsFindEntry(interface, name, HOST_TYPE_IPV4, HOST_NAME_RESOLVER_NBNS);
00067 
00068    //Check whether a matching entry has been found
00069    if(entry)
00070    {
00071       //Host name already resolved?
00072       if(entry->state == DNS_STATE_RESOLVED ||
00073          entry->state == DNS_STATE_PERMANENT)
00074       {
00075          //Return the corresponding IP address
00076          *ipAddr = entry->ipAddr;
00077          //Successful host name resolution
00078          error = NO_ERROR;
00079       }
00080       else
00081       {
00082          //Host name resolution is in progress...
00083          error = ERROR_IN_PROGRESS;
00084       }
00085    }
00086    else
00087    {
00088       //If no entry exists, then create a new one
00089       entry = dnsCreateEntry();
00090 
00091       //Record the host name whose IP address is unknown
00092       strcpy(entry->name, name);
00093 
00094       //Initialize DNS cache entry
00095       entry->type = HOST_TYPE_IPV4;
00096       entry->protocol = HOST_NAME_RESOLVER_NBNS;
00097       entry->interface = interface;
00098 
00099       //Initialize retransmission counter
00100       entry->retransmitCount = NBNS_CLIENT_MAX_RETRIES;
00101       //Send NBNS query
00102       error = nbnsSendQuery(entry);
00103 
00104       //NBNS message successfully sent?
00105       if(!error)
00106       {
00107          //Save the time at which the query message was sent
00108          entry->timestamp = osGetSystemTime();
00109          //Set timeout value
00110          entry->timeout = NBNS_CLIENT_INIT_TIMEOUT;
00111          entry->maxTimeout = NBNS_CLIENT_MAX_TIMEOUT;
00112          //Decrement retransmission counter
00113          entry->retransmitCount--;
00114 
00115          //Switch state
00116          entry->state = DNS_STATE_IN_PROGRESS;
00117          //Host name resolution is in progress
00118          error = ERROR_IN_PROGRESS;
00119       }
00120    }
00121 
00122    //Release exclusive access
00123    osReleaseMutex(&netMutex);
00124 
00125 #if (NET_RTOS_SUPPORT == ENABLED)
00126    //Set default polling interval
00127    delay = DNS_CACHE_INIT_POLLING_INTERVAL;
00128 
00129    //Wait the host name resolution to complete
00130    while(error == ERROR_IN_PROGRESS)
00131    {
00132       //Wait until the next polling period
00133       osDelayTask(delay);
00134 
00135       //Get exclusive access
00136       osAcquireMutex(&netMutex);
00137 
00138       //Search the DNS cache for the specified host name
00139       entry = dnsFindEntry(interface, name, HOST_TYPE_IPV4, HOST_NAME_RESOLVER_NBNS);
00140 
00141       //Check whether a matching entry has been found
00142       if(entry)
00143       {
00144          //Host name successfully resolved?
00145          if(entry->state == DNS_STATE_RESOLVED)
00146          {
00147             //Return the corresponding IP address
00148             *ipAddr = entry->ipAddr;
00149             //Successful host name resolution
00150             error = NO_ERROR;
00151          }
00152       }
00153       else
00154       {
00155          //Host name resolution failed
00156          error = ERROR_FAILURE;
00157       }
00158 
00159       //Release exclusive access
00160       osReleaseMutex(&netMutex);
00161 
00162       //Backoff support for less aggressive polling
00163       delay = MIN(delay * 2, DNS_CACHE_MAX_POLLING_INTERVAL);
00164    }
00165 
00166    //Check status code
00167    if(error)
00168    {
00169       //Failed to resolve host name
00170       TRACE_INFO("Host name resolution failed!\r\n");
00171    }
00172    else
00173    {
00174       //Successful host name resolution
00175       TRACE_INFO("Host name resolved to %s...\r\n", ipAddrToString(ipAddr, NULL));
00176    }
00177 #endif
00178 
00179    //Return status code
00180    return error;
00181 }
00182 
00183 
00184 /**
00185  * @brief Send a NBNS query message
00186  * @param[in] entry Pointer to a valid DNS cache entry
00187  * @return Error code
00188  **/
00189 
00190 error_t nbnsSendQuery(DnsCacheEntry *entry)
00191 {
00192    error_t error;
00193    size_t length;
00194    size_t offset;
00195    NetBuffer *buffer;
00196    NbnsHeader *message;
00197    DnsQuestion *dnsQuestion;
00198    IpAddr destIpAddr;
00199 
00200    //Allocate a memory buffer to hold the NBNS query message
00201    buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset);
00202    //Failed to allocate buffer?
00203    if(buffer == NULL)
00204       return ERROR_OUT_OF_MEMORY;
00205 
00206    //Point to the NBNS header
00207    message = netBufferAt(buffer, offset);
00208 
00209    //Format NBNS query message
00210    message->id = htons(entry->id);
00211    message->qr = 0;
00212    message->opcode = DNS_OPCODE_QUERY;
00213    message->aa = 0;
00214    message->tc = 0;
00215    message->rd = 0;
00216    message->ra = 0;
00217    message->z = 0;
00218    message->b = 1;
00219    message->rcode = DNS_RCODE_NO_ERROR;
00220 
00221    //The NBNS query contains one question
00222    message->qdcount = HTONS(1);
00223    message->ancount = 0;
00224    message->nscount = 0;
00225    message->arcount = 0;
00226 
00227    //Length of the NBNS query message
00228    length = sizeof(DnsHeader);
00229 
00230    //Encode the NetBIOS name
00231    length += nbnsEncodeName(entry->name, message->questions);
00232 
00233    //Point to the corresponding question structure
00234    dnsQuestion = DNS_GET_QUESTION(message, length);
00235    //Fill in question structure
00236    dnsQuestion->qtype = HTONS(DNS_RR_TYPE_NB);
00237    dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN);
00238 
00239    //Update the length of the NBNS query message
00240    length += sizeof(DnsQuestion);
00241 
00242    //Adjust the length of the multi-part buffer
00243    netBufferSetLength(buffer, offset + length);
00244 
00245    //Debug message
00246    TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length);
00247    //Dump message
00248    dnsDumpMessage((DnsHeader *) message, length);
00249 
00250    //The destination address is the broadcast address
00251    destIpAddr.length = sizeof(Ipv4Addr);
00252    ipv4GetBroadcastAddr(entry->interface, &destIpAddr.ipv4Addr);
00253 
00254    //A request packet is always sent to the well known port 137
00255    error = udpSendDatagramEx(entry->interface, NBNS_PORT,
00256       &destIpAddr, NBNS_PORT, buffer, offset, IPV4_DEFAULT_TTL);
00257 
00258    //Free previously allocated memory
00259    netBufferFree(buffer);
00260    //Return status code
00261    return error;
00262 }
00263 
00264 
00265 /**
00266  * @brief Process NBNS response message
00267  * @param[in] interface Underlying network interface
00268  * @param[in] pseudoHeader UDP pseudo header
00269  * @param[in] udpHeader UDP header
00270  * @param[in] message Pointer to the NBNS response message
00271  * @param[in] length Length of the message
00272  **/
00273 
00274 void nbnsProcessResponse(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader,
00275    const UdpHeader *udpHeader, const NbnsHeader *message, size_t length)
00276 {
00277    uint_t i;
00278    size_t pos;
00279    DnsCacheEntry *entry;
00280    DnsResourceRecord *record;
00281    NbnsAddrEntry *addrEntry;
00282 
00283    //The NBNS response shall contain one answer
00284    if(ntohs(message->qdcount) != 0 && ntohs(message->ancount) != 1)
00285       return;
00286 
00287    //Parse NetBIOS name
00288    pos = nbnsParseName(message, length, sizeof(DnsHeader), NULL);
00289    //Invalid name?
00290    if(!pos)
00291       return;
00292 
00293    //Point to the associated resource record
00294    record = DNS_GET_RESOURCE_RECORD(message, pos);
00295    //Point to the resource data
00296    pos += sizeof(DnsResourceRecord);
00297 
00298    //Make sure the resource record is valid
00299    if(pos > length)
00300       return;
00301    if((pos + ntohs(record->rdlength)) > length)
00302       return;
00303 
00304    //Check the class and the type of the resource record
00305    if(ntohs(record->rclass) != DNS_RR_CLASS_IN)
00306       return;
00307    if(ntohs(record->rtype) != DNS_RR_TYPE_NB)
00308       return;
00309 
00310    //Verify the length of the data field
00311    if(ntohs(record->rdlength) < sizeof(NbnsAddrEntry))
00312       return;
00313 
00314    //Loop through DNS cache entries
00315    for(i = 0; i < DNS_CACHE_SIZE; i++)
00316    {
00317       //Point to the current entry
00318       entry = &dnsCache[i];
00319 
00320       //NBNS name resolution in progress?
00321       if(entry->state == DNS_STATE_IN_PROGRESS &&
00322          entry->protocol == HOST_NAME_RESOLVER_NBNS &&
00323          entry->type == HOST_TYPE_IPV4)
00324       {
00325          //Compare identifiers
00326          if(entry->id == ntohs(message->id))
00327          {
00328             //Compare NetBIOS names
00329             if(nbnsCompareName(message, length, sizeof(DnsHeader), entry->name))
00330             {
00331                //Point to the address entry array
00332                addrEntry = (NbnsAddrEntry *) record->rdata;
00333                //Copy the IPv4 address
00334                entry->ipAddr.length = sizeof(Ipv4Addr);
00335                entry->ipAddr.ipv4Addr = addrEntry->addr;
00336 
00337                //Save current time
00338                entry->timestamp = osGetSystemTime();
00339                //Save TTL value
00340                entry->timeout = ntohl(record->ttl) * 1000;
00341                //Limit the lifetime of the NBNS cache entries
00342                entry->timeout = MIN(entry->timeout, NBNS_MAX_LIFETIME);
00343 
00344                //Host name successfully resolved
00345                entry->state = DNS_STATE_RESOLVED;
00346             }
00347          }
00348       }
00349    }
00350 }
00351 
00352 #endif
00353