/***************************************************************************** Function: BOOL DNSIsResolved(IP_ADDR* HostIP) Summary: Determines if the DNS resolution is complete and provides the IP. Description: Call this function to determine if the DNS resolution of an address has been completed. If so, the resolved address will be provided in HostIP. Precondition: DNSResolve or DNSResolveROM has been called. Parameters: HostIP - A pointer to an IP_ADDR structure in which to store the resolved IP address once resolution is complete. Return Values: TRUE - The DNS client has obtained an IP, or the DNS process has encountered an error. HostIP will be 0.0.0.0 on error. Possible errors include server timeout (i.e. DNS server not available), hostname not in the DNS, or DNS server errors. FALSE - The resolution process is still in progress. ***************************************************************************/ BOOL DNSIsResolved(IP_ADDR* HostIP) { static DWORD StartTime; static WORD_VAL SentTransactionID __attribute__((persistent)); static BYTE vARPAttemptCount; static BYTE vDNSAttemptCount; BYTE i; WORD_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; switch(smDNS) { case DNS_START: vARPAttemptCount = 0; vDNSAttemptCount = 0; // No break; case DNS_ARP_START_RESOLVE: ARPResolve(&AppConfig.PrimaryDNSServer); vARPAttemptCount++; StartTime = TickGet(); smDNS = DNS_ARP_RESOLVE; break; case DNS_ARP_RESOLVE: if(!ARPIsResolved(&AppConfig.PrimaryDNSServer, &ResolvedInfo.MACAddr)) { if(TickGet() - StartTime > DNS_TIMEOUT) smDNS = (vARPAttemptCount >= 3u) ? DNS_FAIL : DNS_ARP_START_RESOLVE; break; } ResolvedInfo.IPAddr.Val = AppConfig.PrimaryDNSServer.Val; smDNS = DNS_OPEN_SOCKET; // No break: DNS_OPEN_SOCKET is the correct next state case DNS_OPEN_SOCKET: MySocket = UDPOpen(0, &ResolvedInfo, DNS_PORT); if(MySocket == INVALID_UDP_SOCKET) break; smDNS = DNS_QUERY; // No need to break, we can immediately start resolution case DNS_QUERY: if(!UDPIsPutReady(MySocket)) break; // Put DNS query here SentTransactionID.Val++; UDPPut(SentTransactionID.v[1]);// User chosen transaction ID UDPPut(SentTransactionID.v[0]); UDPPut(0x01); // Standard query with recursion UDPPut(0x00); UDPPut(0x00); // 0x0001 questions UDPPut(0x01); UDPPut(0x00); // 0x0000 answers UDPPut(0x00); UDPPut(0x00); // 0x0000 name server resource records UDPPut(0x00); UDPPut(0x00); // 0x0000 additional records UDPPut(0x00); // Put hostname string to resolve if(DNSHostName) DNSPutString(DNSHostName); else DNSPutROMString(DNSHostNameROM); UDPPut(0x00); // Type: DNS_TYPE_A A (host address) or DNS_TYPE_MX for mail exchange UDPPut(RecordType); UDPPut(0x00); // Class: IN (Internet) UDPPut(0x01); UDPFlush(); StartTime = TickGet(); smDNS = DNS_GET_RESULT; break; case DNS_GET_RESULT: if(!UDPIsGetReady(MySocket)) { if(TickGet() - StartTime > DNS_TIMEOUT) smDNS = DNS_FAIL; break; } // Retrieve the DNS header and de-big-endian it UDPGet(&DNSHeader.TransactionID.v[1]); UDPGet(&DNSHeader.TransactionID.v[0]); // Throw this packet away if it isn't in response to our last query if(DNSHeader.TransactionID.Val != SentTransactionID.Val) { UDPDiscard(); break; } UDPGet(&DNSHeader.Flags.v[1]); UDPGet(&DNSHeader.Flags.v[0]); UDPGet(&DNSHeader.Questions.v[1]); UDPGet(&DNSHeader.Questions.v[0]); UDPGet(&DNSHeader.Answers.v[1]); UDPGet(&DNSHeader.Answers.v[0]); UDPGet(&DNSHeader.AuthoritativeRecords.v[1]); UDPGet(&DNSHeader.AuthoritativeRecords.v[0]); UDPGet(&DNSHeader.AdditionalRecords.v[1]); UDPGet(&DNSHeader.AdditionalRecords.v[0]); // Remove all questions (queries) while(DNSHeader.Questions.Val--) { DNSDiscardName(); UDPGet(&w.v[1]); // Question type UDPGet(&w.v[0]); UDPGet(&w.v[1]); // Question class UDPGet(&w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { DNSDiscardName(); // Throw away response name UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A or MX if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = TRUE; UDPGet(&ResolvedInfo.IPAddr.v[0]); UDPGet(&ResolvedInfo.IPAddr.v[1]); UDPGet(&ResolvedInfo.IPAddr.v[2]); UDPGet(&ResolvedInfo.IPAddr.v[3]); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } // Remove all Authoritative Records while(DNSHeader.AuthoritativeRecords.Val--) { DNSDiscardName(); // Throw away response name UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = TRUE; UDPGet(&ResolvedInfo.IPAddr.v[0]); UDPGet(&ResolvedInfo.IPAddr.v[1]); UDPGet(&ResolvedInfo.IPAddr.v[2]); UDPGet(&ResolvedInfo.IPAddr.v[3]); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } // Remove all Additional Records while(DNSHeader.AdditionalRecords.Val--) { DNSDiscardName(); // Throw away response name UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = TRUE; UDPGet(&ResolvedInfo.IPAddr.v[0]); UDPGet(&ResolvedInfo.IPAddr.v[1]); UDPGet(&ResolvedInfo.IPAddr.v[2]); UDPGet(&ResolvedInfo.IPAddr.v[3]); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } DoneSearchingRecords: UDPDiscard(); UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; smDNS = DNS_DONE; // No break, DNS_DONE is the correct step case DNS_DONE: // Return 0.0.0.0 if DNS resolution failed, otherwise return the // resolved IP address if(!Flags.bits.AddressValid) ResolvedInfo.IPAddr.Val = 0; HostIP->Val = ResolvedInfo.IPAddr.Val; return TRUE; case DNS_FAIL: // If 3 attempts or more, quit if(vDNSAttemptCount >= 2u) { // Return an invalid IP address 0.0.0.0 if we can't finish ARP or DNS query step HostIP->Val = 0x00000000; return TRUE; } vDNSAttemptCount++; // Swap primary and secondary DNS servers if there is a secondary DNS server programmed if(AppConfig.SecondaryDNSServer.Val) { AppConfig.PrimaryDNSServer.Val ^= AppConfig.SecondaryDNSServer.Val; AppConfig.SecondaryDNSServer.Val ^= AppConfig.PrimaryDNSServer.Val; AppConfig.PrimaryDNSServer.Val ^= AppConfig.SecondaryDNSServer.Val; // Start another ARP resolution for the secondary server (now primary) vARPAttemptCount = 0; if(MySocket != INVALID_UDP_SOCKET) { UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; } smDNS = DNS_ARP_START_RESOLVE; } break; } return FALSE; }
/***************************************************************************** Function: void DNSClientTask(void) Summary: DNS client state machine Description: Process the DNS client state machine Precondition: DNSClientInit has been called. Parameters: None Return Values: None ***************************************************************************/ void DNSClientTask(void) { uint8_t i; TCPIP_UINT16_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; switch(smDNS) { case DNS_IDLE: break; // nothing to do case DNS_START: smDNS = DNSRetry(DNS_START); stateStartTime = 0; // flag the first Open try break; case DNS_OPEN_SOCKET: DNSSocket = UDPOpenClient(IP_ADDRESS_TYPE_IPV4, DNS_CLIENT_PORT, (IP_MULTI_ADDRESS*)(DNSServers + vDNSServerIx)); if(DNSSocket == INVALID_UDP_SOCKET) { if(stateStartTime == 0) { stateStartTime = SYS_TICK_Get(); } else if(SYS_TICK_Get() - stateStartTime > (DNS_CLIENT_OPEN_TMO * SYS_TICK_TicksPerSecondGet())) { smDNS = DNS_FAIL_OPEN_TMO; } break; } // got a valid UDP socket UDPSocketSetNet(DNSSocket, pDNSNet); stateStartTime = SYS_TICK_Get(); smDNS = DNS_QUERY; // no break, start sending the query; case DNS_QUERY: if(!UDPIsOpened(DNSSocket) || (UDPIsTxPutReady(DNSSocket, 18 + strlen (DNSHostName)) < (18 + strlen (DNSHostName)))) { if(SYS_TICK_Get() - stateStartTime > (DNS_CLIENT_OPEN_TMO * SYS_TICK_TicksPerSecondGet())) { smDNS = DNS_FAIL_OPEN_TMO; } break; // wait some more } // Put DNS query here SentTransactionID.Val = (uint16_t)rand(); UDPPut(DNSSocket, SentTransactionID.v[1]);// User chosen transaction ID UDPPut(DNSSocket, SentTransactionID.v[0]); UDPPut(DNSSocket, 0x01); // Standard query with recursion UDPPut(DNSSocket, 0x00); UDPPut(DNSSocket, 0x00); // 0x0001 questions UDPPut(DNSSocket, 0x01); UDPPut(DNSSocket, 0x00); // 0x0000 answers UDPPut(DNSSocket, 0x00); UDPPut(DNSSocket, 0x00); // 0x0000 name server resource records UDPPut(DNSSocket, 0x00); UDPPut(DNSSocket, 0x00); // 0x0000 additional records UDPPut(DNSSocket, 0x00); // Put hostname string to resolve DNSPutString(DNSSocket, DNSHostName); UDPPut(DNSSocket, 0x00); // Type: DNS_TYPE_A A (host address) or DNS_TYPE_MX for mail exchange UDPPut(DNSSocket, RecordType); UDPPut(DNSSocket, 0x00); // Class: IN (Internet) UDPPut(DNSSocket, 0x01); UDPFlush(DNSSocket); stateStartTime = SYS_TICK_Get(); smDNS = DNS_GET_RESULT; break; case DNS_GET_RESULT: if(!UDPIsGetReady(DNSSocket)) { if(SYS_TICK_Get() - stateStartTime > (DNS_CLIENT_SERVER_TMO * SYS_TICK_TicksPerSecondGet())) { smDNS = DNS_FAIL_SERVER; } break; } // Retrieve the DNS header and de-big-endian it UDPGet(DNSSocket, &DNSHeader.TransactionID.v[1]); UDPGet(DNSSocket, &DNSHeader.TransactionID.v[0]); // Throw this packet away if it isn't in response to our last query if(DNSHeader.TransactionID.Val != SentTransactionID.Val) { UDPDiscard(DNSSocket); break; } UDPGet(DNSSocket, &DNSHeader.Flags.v[1]); UDPGet(DNSSocket, &DNSHeader.Flags.v[0]); UDPGet(DNSSocket, &DNSHeader.Questions.v[1]); UDPGet(DNSSocket, &DNSHeader.Questions.v[0]); UDPGet(DNSSocket, &DNSHeader.Answers.v[1]); UDPGet(DNSSocket, &DNSHeader.Answers.v[0]); UDPGet(DNSSocket, &DNSHeader.AuthoritativeRecords.v[1]); UDPGet(DNSSocket, &DNSHeader.AuthoritativeRecords.v[0]); UDPGet(DNSSocket, &DNSHeader.AdditionalRecords.v[1]); UDPGet(DNSSocket, &DNSHeader.AdditionalRecords.v[0]); // Remove all questions (queries) while(DNSHeader.Questions.Val--) { DNSDiscardName(DNSSocket); UDPGet(DNSSocket, &w.v[1]); // Question type UDPGet(DNSSocket, &w.v[0]); UDPGet(DNSSocket, &w.v[1]); // Question class UDPGet(DNSSocket, &w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { DNSDiscardName(DNSSocket); // Throw away response name UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A, MX, or AAAA if( DNSAnswerHeader.ResponseClass.Val == 0x0001u) // Internet class { if (DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV4; UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[0]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[1]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[2]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[3]); goto DoneSearchingRecords; } else if (DNSAnswerHeader.ResponseType.Val == 0x001Cu && DNSAnswerHeader.ResponseLen.Val == 0x0010u) { if (RecordType != DNS_TYPE_AAAA) { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } break; } Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV6; UDPGetArray (DNSSocket, (void *)&ResolvedAddress.ipv6Address, sizeof (IPV6_ADDR)); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } // Remove all Authoritative Records while(DNSHeader.AuthoritativeRecords.Val--) { DNSDiscardName(DNSSocket); // Throw away response name UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseClass.Val == 0x0001u) // Internet class { if (DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV4; UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[0]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[1]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[2]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[3]); goto DoneSearchingRecords; } else if (DNSAnswerHeader.ResponseType.Val == 0x001Cu && DNSAnswerHeader.ResponseLen.Val == 0x0010u) { if (RecordType != DNS_TYPE_AAAA) { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } break; } Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV6; UDPGetArray (DNSSocket, (void *)&ResolvedAddress.ipv6Address, sizeof (IPV6_ADDR)); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } // Remove all Additional Records while(DNSHeader.AdditionalRecords.Val--) { DNSDiscardName(DNSSocket); // Throw away response name UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(DNSSocket, &DNSAnswerHeader.ResponseType.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(DNSSocket, &DNSAnswerHeader.ResponseClass.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(DNSSocket, &DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A or MX, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseClass.Val == 0x0001u) // Internet class { if (DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseLen.Val == 0x0004u) { Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV4; UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[0]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[1]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[2]); UDPGet(DNSSocket, &ResolvedAddress.ipv4Address.v[3]); goto DoneSearchingRecords; } else if (DNSAnswerHeader.ResponseType.Val == 0x001Cu && DNSAnswerHeader.ResponseLen.Val == 0x0010u) { if (RecordType != DNS_TYPE_AAAA) { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } break; } Flags.bits.AddressValid = true; Flags.bits.AddressType = IP_ADDRESS_TYPE_IPV6; UDPGetArray (DNSSocket, (void *)&ResolvedAddress.ipv6Address, sizeof (IPV6_ADDR)); goto DoneSearchingRecords; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(DNSSocket, &i); } } } DoneSearchingRecords: UDPDiscard(DNSSocket); _DNSReleaseSocket(); if(Flags.bits.AddressValid) { smDNS = DNS_DONE; } else { smDNS = DNSRetry(DNS_FAIL_SERVER); } break; // done case DNS_FAIL_ARP: // see if there is other server we may try smDNS = DNSRetry(DNS_FAIL_ARP); break; case DNS_FAIL_SERVER: smDNS = DNSRetry(DNS_FAIL_SERVER); break; default: // DNS_DONE, DNS_FAIL_ARP_TMO, DNS_FAIL_OPEN_TMO, DNS_FAIL_SERVER_TMO // either done or some error state break; } #if DNS_CLIENT_VERSION_NO >= 2 dnsTickPending = 0; #endif // DNS_CLIENT_VERSION_NO >= 2 }
/** * Call DNSIsResolved() until the host is resolved. * You cannot start two DNS resolution proceedures concurrently. * You must not modify *Hostname until DNSIsResolved() returns TRUE. * * @preCondition DNSResolve() was called. * * @param HostIP 4 byte IP address */ BOOL DNSIsResolved(IP_ADDR *HostIP) { static UDP_SOCKET MySocket; static NODE_INFO Remote; static TICK StartTime; BYTE i; WORD_VAL w; DNS_HEADER DNSHeader; DNS_ANSWER_HEADER DNSAnswerHeader; IP_ADDR tmpIpAddr; switch(smDNS) { case DNS_HOME: tmpIpAddr.v[0] = MY_DNS_BYTE1; tmpIpAddr.v[1] = MY_DNS_BYTE2; tmpIpAddr.v[2] = MY_DNS_BYTE3; tmpIpAddr.v[3] = MY_DNS_BYTE4; ARPResolve(&tmpIpAddr); StartTime = TickGet(); smDNS++; break; case DNS_RESOLVE_ARP: if(!ARPIsResolved(&tmpIpAddr, &Remote.MACAddr)) { if(TickGet() - StartTime > DNS_TIMEOUT) { smDNS--; } break; } Remote.IPAddr.Val = tmpIpAddr.Val; smDNS++; // No need to break, we can immediately start resolution case DNS_OPEN_SOCKET: MySocket = UDPOpen(0, &Remote, DNS_PORT); if(MySocket == INVALID_UDP_SOCKET) { #if (DEBUG_DNS >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Could not open UDP socket #endif break; } smDNS++; // No need to break, we can immediately start resolution case DNS_QUERY: if(!UDPIsPutReady(MySocket)) break; // Put DNS query here UDPPut(0x12); // User chosen ID UDPPut(0x34); UDPPut(0x01); // Standard query with recursion UDPPut(0x00); UDPPut(0x00); // 0x0001 questions UDPPut(0x01); UDPPut(0x00); // 0x0000 answers UDPPut(0x00); UDPPut(0x00); // 0x0000 name server resource records UDPPut(0x00); UDPPut(0x00); // 0x0000 additional records UDPPut(0x00); // Put hostname string to resolve DNSPutString(DNSHostName); UDPPut(0x00); // Type: A (host address) UDPPut(0x01); UDPPut(0x00); // Class: IN (Internet) UDPPut(0x01); UDPFlush(); StartTime = TickGet(); smDNS++; break; case DNS_GET_RESULT: if(!UDPIsGetReady(MySocket)) { if(TickGet() - StartTime > DNS_TIMEOUT) { smDNS--; } break; } // Retrieve the DNS header and de-big-endian it UDPGet(&DNSHeader.TransactionID.v[1]); UDPGet(&DNSHeader.TransactionID.v[0]); UDPGet(&DNSHeader.Flags.v[1]); UDPGet(&DNSHeader.Flags.v[0]); UDPGet(&DNSHeader.Questions.v[1]); UDPGet(&DNSHeader.Questions.v[0]); UDPGet(&DNSHeader.Answers.v[1]); UDPGet(&DNSHeader.Answers.v[0]); UDPGet(&DNSHeader.AuthoritativeRecords.v[1]); UDPGet(&DNSHeader.AuthoritativeRecords.v[0]); UDPGet(&DNSHeader.AdditionalRecords.v[1]); UDPGet(&DNSHeader.AdditionalRecords.v[0]); // Remove all questions while(DNSHeader.Questions.Val--) { DNSGetString(NULL); UDPGet(&w.v[1]); // Question type UDPGet(&w.v[0]); UDPGet(&w.v[1]); // Question class UDPGet(&w.v[0]); } // Scan through answers while(DNSHeader.Answers.Val--) { UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name UDPGet(&DNSAnswerHeader.ResponseName.v[0]); UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type UDPGet(&DNSAnswerHeader.ResponseType.v[0]); UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); // Make sure that this is a 4 byte IP address, response type A, class 1 // Check if this is Type A if( DNSAnswerHeader.ResponseType.Val == 0x0001u && DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class DNSAnswerHeader.ResponseLen.Val == 0x0004u) { UDPGet(&HostIP->v[0]); UDPGet(&HostIP->v[1]); UDPGet(&HostIP->v[2]); UDPGet(&HostIP->v[3]); break; } else { while(DNSAnswerHeader.ResponseLen.Val--) { UDPGet(&i); } } } UDPDiscard(); UDPClose(MySocket); MySocket = INVALID_UDP_SOCKET; smDNS++; // No need to break, we are done and need to return TRUE case DNS_DONE: return TRUE; } return FALSE; }