Subversion Repositories HomeAutomation

Rev

Rev 363 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *  DNS Client Module for Microchip TCP/IP Stack
  4.  *   -Provides DNS resolution (client)
  5.  *
  6.  *********************************************************************
  7.  * FileName:        DNS.c
  8.  * Dependencies:    UDP, ARP, Tick
  9.  * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
  10.  * Complier:        Microchip C18 v3.02 or higher
  11.  *                  Microchip C30 v2.01 or higher
  12.  * Company:         Microchip Technology, Inc.
  13.  *
  14.  * Software License Agreement
  15.  *
  16.  * This software is owned by Microchip Technology Inc. ("Microchip")
  17.  * and is supplied to you for use exclusively as described in the
  18.  * associated software agreement.  This software is protected by
  19.  * software and other intellectual property laws.  Any use in
  20.  * violation of the software license may subject the user to criminal
  21.  * sanctions as well as civil liability.  Copyright 2006 Microchip
  22.  * Technology Inc.  All rights reserved.
  23.  *
  24.  * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL
  25.  * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
  26.  * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
  27.  * INFRINGEMENT.  Microchip shall in no event be liable for special,
  28.  * incidental, or consequential damages.
  29.  *
  30.  *
  31.  * Author               Date    Comment
  32.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  33.  * Howard Schlunder     7/31/06 Original
  34.  ********************************************************************/
  35. #define THIS_IS_DNS
  36.  
  37. #include "..\Include\Compiler.h"
  38. #include "..\Include\UDP.h"
  39. #include "..\Include\Tick.h"
  40. #include "..\Include\ARP.h"
  41. #include "..\Include\ARPTsk.h"
  42. #include "..\Include\DNS.h"
  43. #include "..\Include\Helpers.h"
  44.  
  45. #if defined(STACK_USE_DNS)
  46.  
  47. #define DNS_PORT        53
  48. #define DNS_TIMEOUT     (TICK_1S*2)
  49.  
  50.  
  51. static BYTE *DNSHostName;
  52. static enum
  53. {
  54.     DNS_HOME = 0,
  55.     DNS_RESOLVE_ARP,
  56.     DNS_OPEN_SOCKET,
  57.     DNS_QUERY,
  58.     DNS_GET_RESULT,
  59.     DNS_DONE
  60. } smDNS = DNS_DONE;
  61.  
  62. typedef struct _DNS_HEADER
  63. {
  64.     WORD_VAL TransactionID;
  65.     WORD_VAL Flags;
  66.     WORD_VAL Questions;
  67.     WORD_VAL Answers;
  68.     WORD_VAL AuthoritativeRecords;
  69.     WORD_VAL AdditionalRecords;
  70. } DNS_HEADER;
  71.  
  72. typedef struct _DNS_ANSWER_HEADER
  73. {
  74.     WORD_VAL    ResponseName;
  75.     WORD_VAL    ResponseType;
  76.     WORD_VAL    ResponseClass;
  77.     DWORD_VAL   ResponseTTL;
  78.     WORD_VAL    ResponseLen;
  79. } DNS_ANSWER_HEADER;
  80.  
  81. static void DNSPutString(BYTE *String);
  82. static void DNSGetString(BYTE *String);
  83.  
  84. /*********************************************************************
  85.  * Function:        void DNSResolve(BYTE *Hostname)
  86.  *
  87.  * PreCondition:    Stack is initialized()
  88.  *
  89.  * Input:           *Hostname: Null terminated string specifying the
  90.  *                             host address to resolve to an IP
  91.  *                             address.
  92.  *
  93.  * Output:          None
  94.  *
  95.  * Side Effects:    None
  96.  *
  97.  * Overview:        Call DNSIsResolved() until the host is resolved.
  98.  *
  99.  * Note:            A UDP socket must be available before this
  100.  *                  function is called.  It is freed at the end of
  101.  *                  the resolution.  MAX_UDP_SOCKETS may need to be
  102.  *                  increased if other modules use UDP sockets.
  103.  *
  104.  *                  You must not modify *Hostname until DNSIsResolved()
  105.  *                  returns TRUE.
  106.  ********************************************************************/
  107. void DNSResolve(BYTE *Hostname)
  108. {
  109.     DNSHostName = Hostname;
  110.     smDNS = DNS_HOME;
  111. }
  112.  
  113.  
  114. /*********************************************************************
  115.  * Function:        BOOL DNSIsResolved(IP_ADDR *HostIP)
  116.  *
  117.  * PreCondition:    DNSResolve() was called.
  118.  *
  119.  * Input:           HostIP: Pointer to IP_ADDR structure to store the
  120.  *                          returned host IP address when DNS
  121.  *                          resolution is complete.
  122.  *
  123.  * Output:          *HostIP, 4 byte IP address
  124.  *
  125.  * Side Effects:    None
  126.  *
  127.  * Overview:        Call DNSIsResolved() until the host is resolved.
  128.  *
  129.  * Note:            You cannot start two DNS resolution proceedures
  130.  *                  concurrently.
  131.  *
  132.  *                  You must not modify *Hostname until DNSIsResolved()
  133.  *                  returns TRUE.
  134.  ********************************************************************/
  135. BOOL DNSIsResolved(IP_ADDR *HostIP)
  136. {
  137.     static UDP_SOCKET   MySocket;
  138.     static NODE_INFO    Remote;
  139.     static TICK         StartTime;
  140.     BYTE                i;
  141.     WORD_VAL            w;
  142.     DNS_HEADER          DNSHeader;
  143.     DNS_ANSWER_HEADER   DNSAnswerHeader;
  144.  
  145.     switch(smDNS)
  146.     {
  147.         case DNS_HOME:
  148.             ARPResolve(&AppConfig.PrimaryDNSServer);
  149.             StartTime = tickGet();
  150.             smDNS++;
  151.             break;
  152.         case DNS_RESOLVE_ARP:
  153.             if(!ARPIsResolved(&AppConfig.PrimaryDNSServer, &Remote.MACAddr))
  154.             {
  155.                 if(tickGet() - StartTime > DNS_TIMEOUT)
  156.                 {
  157.                     smDNS--;
  158.                 }
  159.                 break;
  160.             }
  161.             Remote.IPAddr.Val = AppConfig.PrimaryDNSServer.Val;
  162.             smDNS++;
  163.             // No need to break, we can immediately start resolution
  164.  
  165.         case DNS_OPEN_SOCKET:
  166.             MySocket = UDPOpen(0, &Remote, DNS_PORT);
  167.             if(MySocket == INVALID_UDP_SOCKET)
  168.                 break;
  169.  
  170.             smDNS++;
  171.             // No need to break, we can immediately start resolution
  172.            
  173.         case DNS_QUERY:
  174.             if(!UDPIsPutReady(MySocket))
  175.                 break;
  176.            
  177.             // Put DNS query here
  178.             UDPPut(0x12);       // User chosen ID
  179.             UDPPut(0x34);
  180.             UDPPut(0x01);       // Standard query with recursion
  181.             UDPPut(0x00);  
  182.             UDPPut(0x00);       // 0x0001 questions
  183.             UDPPut(0x01);
  184.             UDPPut(0x00);       // 0x0000 answers
  185.             UDPPut(0x00);
  186.             UDPPut(0x00);       // 0x0000 name server resource records
  187.             UDPPut(0x00);
  188.             UDPPut(0x00);       // 0x0000 additional records
  189.             UDPPut(0x00);
  190.  
  191.             // Put hostname string to resolve
  192.             DNSPutString(DNSHostName);
  193.  
  194.             UDPPut(0x00);       // Type: A (host address)
  195.             UDPPut(0x01);
  196.             UDPPut(0x00);       // Class: IN (Internet)
  197.             UDPPut(0x01);
  198.  
  199.             UDPFlush();
  200.             StartTime = tickGet();
  201.             smDNS++;
  202.             break;
  203.  
  204.         case DNS_GET_RESULT:
  205.             if(!UDPIsGetReady(MySocket))
  206.             {
  207.                 if(tickGet() - StartTime > DNS_TIMEOUT)
  208.                 {
  209.                     smDNS--;
  210.                 }
  211.                 break;
  212.             }
  213.  
  214.             // Retrieve the DNS header and de-big-endian it
  215.             UDPGet(&DNSHeader.TransactionID.v[1]);
  216.             UDPGet(&DNSHeader.TransactionID.v[0]);
  217.             UDPGet(&DNSHeader.Flags.v[1]);
  218.             UDPGet(&DNSHeader.Flags.v[0]);
  219.             UDPGet(&DNSHeader.Questions.v[1]);
  220.             UDPGet(&DNSHeader.Questions.v[0]);
  221.             UDPGet(&DNSHeader.Answers.v[1]);
  222.             UDPGet(&DNSHeader.Answers.v[0]);
  223.             UDPGet(&DNSHeader.AuthoritativeRecords.v[1]);
  224.             UDPGet(&DNSHeader.AuthoritativeRecords.v[0]);
  225.             UDPGet(&DNSHeader.AdditionalRecords.v[1]);
  226.             UDPGet(&DNSHeader.AdditionalRecords.v[0]);
  227.  
  228.             // Remove all questions
  229.             while(DNSHeader.Questions.Val--)
  230.             {
  231.                 DNSGetString(NULL);
  232.                 UDPGet(&w.v[1]);        // Question type
  233.                 UDPGet(&w.v[0]);
  234.                 UDPGet(&w.v[1]);        // Question class
  235.                 UDPGet(&w.v[0]);
  236.             }
  237.            
  238.             // Scan through answers
  239.             while(DNSHeader.Answers.Val--)
  240.             {
  241.                 UDPGet(&DNSAnswerHeader.ResponseName.v[1]);     // Response name
  242.                 UDPGet(&DNSAnswerHeader.ResponseName.v[0]);
  243.                 UDPGet(&DNSAnswerHeader.ResponseType.v[1]);     // Response type
  244.                 UDPGet(&DNSAnswerHeader.ResponseType.v[0]);
  245.                 UDPGet(&DNSAnswerHeader.ResponseClass.v[1]);    // Response class
  246.                 UDPGet(&DNSAnswerHeader.ResponseClass.v[0]);
  247.                 UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]);      // Time to live
  248.                 UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]);
  249.                 UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]);
  250.                 UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]);
  251.                 UDPGet(&DNSAnswerHeader.ResponseLen.v[1]);      // Response length
  252.                 UDPGet(&DNSAnswerHeader.ResponseLen.v[0]);
  253.  
  254.                 // Make sure that this is a 4 byte IP address, response type A, class 1
  255.                 // Check if this is Type A
  256.                 if( DNSAnswerHeader.ResponseType.Val    == 0x0001 &&
  257.                     DNSAnswerHeader.ResponseClass.Val   == 0x0001 && // Internet class
  258.                     DNSAnswerHeader.ResponseLen.Val     == 0x0004)
  259.                 {
  260.                     UDPGet(&HostIP->v[0]);
  261.                     UDPGet(&HostIP->v[1]);
  262.                     UDPGet(&HostIP->v[2]);
  263.                     UDPGet(&HostIP->v[3]);
  264.                     break;
  265.                 }
  266.                 else
  267.                 {
  268.                     while(DNSAnswerHeader.ResponseLen.Val--)
  269.                     {
  270.                         UDPGet(&i);
  271.                     }
  272.                 }
  273.             }
  274.  
  275.             UDPDiscard();
  276.             UDPClose(MySocket);
  277.             MySocket = INVALID_UDP_SOCKET;
  278.             smDNS++;
  279.             // No need to break, we are done and need to return TRUE
  280.  
  281.         case DNS_DONE:
  282.             return TRUE;
  283.     }
  284.    
  285.     return FALSE;
  286. }
  287.  
  288. static void DNSPutString(BYTE *String)
  289. {
  290.     BYTE *RightPtr;
  291.     BYTE i;
  292.     BYTE Len;
  293.  
  294.     RightPtr = String;
  295.  
  296.     while(1)
  297.     {
  298.         do
  299.         {
  300.             i = *RightPtr++;
  301.         } while((i != 0x00) && (i != '.') && (i != '/'));
  302.    
  303.         // Put the length parameter
  304.         Len = (BYTE)(RightPtr-String-1);
  305.         UDPPut(Len);
  306.         while(Len--)
  307.         {
  308.             UDPPut(*String++);
  309.         }
  310.         if(i == 0x00 || i == '/')
  311.             break;
  312.  
  313.         // Skip over the '.' in the input string
  314.         String++;
  315.     }
  316.    
  317.     // Put the string terminator character
  318.     UDPPut(0x00);
  319. }
  320.  
  321. static void DNSGetString(BYTE *String)
  322. {
  323.     BYTE i;
  324.     BYTE j;
  325.  
  326.     if(String == NULL)
  327.     {
  328.         UDPGet(&i);
  329.         while(i)
  330.         {
  331.             while(i--)
  332.             {
  333.                 UDPGet(&j);
  334.             }
  335.             UDPGet(&i);
  336.         }
  337.     }
  338.     else
  339.     {
  340.         UDPGet(&i);
  341.         while(i)
  342.         {
  343.             while(i--)
  344.             {
  345.                 UDPGet(String);
  346.                 String++;
  347.             }
  348.             UDPGet(&i);
  349.         }
  350.     }
  351. }
  352.  
  353.  
  354. #endif  //#if defined(STACK_USE_DNS)
  355.