/**************************************************************************** Function: BOOL UDPNodeInfoFromIP(IP_ADDR ipAddrRemote, NODE_INFO * pnodeInfo, unsigned int cSecTimeout) Description: Does an ARP to resolve the MAC address for a give IP Address Precondition: UDP stack has to be up an running Parameters: ipAddrRemote - an IP_ADDR with the IP address of the remote machine you want to discover the MAC address for. pnoeInfo - a pointer to an empty NODE_INFO structure. The IP address and MAC will be loaded into the sturcture cSecTimout - The maximum number of seconds to wait for the arp address to be resolved if it can't be done in this amount of time, return with FALSE as unresolved. Returns: TRUE if the MAC address was resolved, FALSE if it was not. Remarks: None ***************************************************************************/ static BOOL UDPNodeInfoFromIP(IP_ADDR ipAddrRemote, NODE_INFO * pnodeInfo, unsigned int cSecTimeout) { DWORD t = 0; pnodeInfo->IPAddr = ipAddrRemote; // if this the broadcast IP address, then set the broadcast mac. if(ipAddrRemote.Val == 0xFFFFFFFF) { memset(&pnodeInfo->MACAddr, 0xFF, sizeof(pnodeInfo->MACAddr)); return(TRUE); } // resolve the IP address to get a MAC ARPResolve(&ipAddrRemote); t = TickGet(); while( !ARPIsResolved(&ipAddrRemote, &pnodeInfo->MACAddr) ) { if((TickGet() - t) >= (cSecTimeout * TICK_SECOND)) { return(FALSE); } ChipKITPeriodicTasks(); } return(TRUE); }
/********************************************************************* * Function: LONG ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ LONG ICMPGetReply(void) { switch(ICMPState) { case SM_ARP_RESOLVE: // See if the ARP reponse was successfully received if(ARPIsResolved(&ICMPRemote.IPAddr, &ICMPRemote.MACAddr)) { // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Create IP header in TX memory IPPutHeader(&ICMPRemote, IP_PROT_ICMP, sizeof(ICMP_HEADER) + 2); MACPutArray((BYTE*)&ICMPHeader, sizeof(ICMPHeader)); MACPut(0x00); // Send two dummy bytes as ping payload MACPut(0x00); // (needed for compatibility with some buggy NAT routers) MACFlush(); // MAC Address resolved and echo sent, advance state ICMPState = SM_GET_ECHO; return -2; } // See if the ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No ARP response back yet return -2; case SM_GET_ECHO: // See if the echo was successfully received if(ICMPFlags.bReplyValid) { return (LONG)ICMPTimer; } // See if the ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No echo response back yet return -2; // SM_IDLE or illegal/impossible state: default: return -1; } }
/********************************************************************* * Function: SHORT ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ SHORT ICMPGetReply(void) { switch(ICMPState) { case SM_IDLE: return -1; case SM_ARP_RESOLVE: // See if the ARP reponse was successfully received if(ARPIsResolved(&ICMPRemote.IPAddr, &ICMPRemote.MACAddr)) { // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Wait for TX hardware to become available (finish transmitting // any previous packet) while(!IPIsTxReady()); // Create IP header in TX memory IPPutHeader(&ICMPRemote, IP_PROT_ICMP, sizeof(ICMP_HEADER)); MACPutArray((BYTE*)&ICMPHeader, sizeof(ICMPHeader)); MACFlush(); // MAC Address resolved and echo sent, advance state ICMPState = SM_GET_ECHO; return -2; } // See if the ARP/echo request timed out if((WORD)TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No ARP response back yet return -2; case SM_GET_ECHO: // See if the echo was successfully received if(ICMPFlags.bReplyValid) { return (SHORT)ICMPTimer; } // See if the ARP/echo request timed out if((WORD)TickGet() - ICMPTimer > ICMP_TIMEOUT) { ICMPState = SM_IDLE; return -1; } // No echo response back yet return -2; } }
/** * UDPClientOpen - Create a UDP client on specified port, try more time for arp request. * \param udpaddr IP address of server * \param udpport Remote Port of UDP server * \return The number of current socket or 0 if an error occured during the opening of the socket. */ BYTE UDPClientOpen (char *udpaddr, char udpport[]) { static NODE_INFO Server; StringToIPAddress((BYTE*) udpaddr, &Server.IPAddr); ARPResolveMAC((char*) &(Server.IPAddr)); if(ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) return UDPGenericOpen(0, &Server, udpport); else return 0; }
ARP_RESULT ARPEntryGet(TCPIP_NET_HANDLE hNet, IP_ADDR* ipAdd, MAC_ADDR* pHwAdd) { NET_CONFIG *pIf; pIf = _TCPIPStackHandleToNet(hNet); if(pIf) { if(ARPIsResolved(pIf, ipAdd, pHwAdd)) { return ARP_RES_OK; } } return ARP_RES_NO_ENTRY; }
/********************************************************************* * Function: TFTP_RESULT TFTPIsOpened(void) * * PreCondition: TFTPOpen() is already called. * * Input: None * * Output: TFTP_OK if previous call to TFTPOpen is complete * * TFTP_TIMEOUT if remote host did not respond to * previous ARP request. * * TFTP_NOT_READY if remote has still not responded * and timeout has not expired. * * Side Effects: None * * Overview: Waits for ARP reply and opens a UDP socket * to perform further TFTP operations. * * Note: Once opened, application may keep TFTP socket * open and future TFTP operations. * If TFTPClose() is called to close the connection * TFTPOpen() must be called again before performing * any other TFTP operations. ********************************************************************/ TFTP_RESULT TFTPIsOpened(void) { switch(_tftpState) { default: DEBUG(printf("Resolving remote IP...\n")); // Check to see if adddress is resolved. if ( ARPIsResolved(&MutExVar.group1._hostInfo.IPAddr, &MutExVar.group1._hostInfo.MACAddr) ) { _tftpSocket = UDPOpen(TFTP_CLIENT_PORT, &MutExVar.group1._hostInfo, TFTP_SERVER_PORT); if( _tftpSocket == INVALID_UDP_SOCKET ) { #if (DEBUG_TFTPC >= LOG_ERROR) debugPutMsg(1); //@mxd:1:Could not open UDP socket #endif } _tftpState = SM_TFTP_READY; } else break; case SM_TFTP_READY: // Wait for UDP to be ready. Immediately after this user will // may TFTPGetFile or TFTPPutFile and we have to make sure that // UDP is read to transmit. These functions do not check for // UDP to get ready. if ( UDPIsPutReady(_tftpSocket) ) return TFTP_OK; } // Make sure that we do not do this forever. if ( TickGetDiff(TickGet(), _tftpStartTick) >= TFTP_ARP_TIMEOUT_VAL ) { _tftpStartTick = TickGet(); // Forget about all previous attempts. _tftpRetries = 1; return TFTP_TIMEOUT; } return TFTP_NOT_READY; }
/** * UDPClientOpen - Create a UDP client on specified port, try more time for arp request. * \param udpaddr IP address of server * \param udpport Remote Port of UDP server * \return The number of current socket or 0 if an error occured during the opening of the socket. */ BYTE UDPClientOpen (char *udpaddr, char udpport[]) { #if defined (FLYPORT) if (WFStatus != TURNED_OFF) #endif { static NODE_INFO Server; StringToIPAddress((BYTE*) udpaddr, &Server.IPAddr); ARPResolveMAC((char*) &(Server.IPAddr)); vTaskDelay(30); if(ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) return UDPGenericOpen(0, &Server, udpport); else return 0; } return 0; }
void AutoIPTasks(NET_CONFIG* pConfig) { // uint8_t i; TCPIP_MAC_HANDLE hMac; // for (i = 0; i < NETWORK_INTERFACES; i++) { LoadState(_TCPIPStackNetIx(pConfig)); hMac = _TCPIPStackNetToMac(pConfig); AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(hMac); if(AutoIPClient.flags.bits.bCurrentLinkState != AutoIPClient.flags.bits.bLastLinkState) { AutoIPClient.flags.bits.bLastLinkState = AutoIPClient.flags.bits.bCurrentLinkState; if(!AutoIPClient.flags.bits.bCurrentLinkState) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val; pConfig->MyMask.Val = pConfig->DefaultMask.Val; } else { AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } } #if defined (TCPIP_STACK_USE_DHCP_CLIENT) if (DHCPIsBound(pConfig)) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AutoIPClient.flags.bits.bLastDHCPState = true; } else { if (AutoIPClient.flags.bits.bLastDHCPState == true) { if (AutoIPClient.flags.bits.bCurrentLinkState) AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } AutoIPClient.flags.bits.bLastDHCPState = false; } #endif if (AutoIPClient.flags.bits.gDisableAutoIP == true) { AutoIPClient.flags.bits.bConfigureAutoIP = false; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; } switch (AutoIPClient.smAUTOIPState) { // Default no-AutoIP case case SM_AUTOIP_DISABLED: break; // Initializes the random number generator with a seed based on the MAC address case SM_AUTOIP_INIT_RNG: AutoIPRandSeed (((uint32_t)pConfig->MyMACAddr.v[0] + ((uint32_t)pConfig->MyMACAddr.v[1] << 8) + \ ((uint32_t)pConfig->MyMACAddr.v[2] << 16) + ((uint32_t)pConfig->MyMACAddr.v[3] << 24) + \ ((uint32_t)pConfig->MyMACAddr.v[4]) + ((uint32_t)pConfig->MyMACAddr.v[5] << 8)), pConfig); AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; // Check the address to see if it's in use before we write it into NetConfig case SM_AUTOIP_CHECK_ADDRESS: if (AutoIPClient.flags.bits.checkAddress == false) { AutoIPClient.flags.bits.checkAddress = true; pConfig->MyMask.Val = 0x00000000; // Generate a random IP address (based on the MAC address) to try and claim. // Dynamic link-local addresses can fall within the range: // 169.254.1.0 - 169.254.254.255 AutoIPClient.packet.TargetIPAddr.byte.MB = AutoIPRand(pConfig) % 256; AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(pConfig) % 254) + 1; AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9; ARPResolve (pConfig, &AutoIPClient.packet.TargetIPAddr); AutoIPClient.eventTime = SYS_TICK_Get(); } if (!ARPIsResolved (pConfig, &AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr)) { if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet()) { AutoIPClient.smAUTOIPState = SM_AUTOIP_SETUP_MESSAGE; } } else { AutoIPClient.flags.bits.checkAddress = false; } break; // Set up an ARP packet case SM_AUTOIP_SETUP_MESSAGE: AutoIPClient.flags.bits.checkAddress = false; // Set the bConfigureAutoIP flag- This flag will cause an AutoIP conflict // if a response packet is received from the address we're trying to claim. AutoIPClient.flags.bits.bConfigureAutoIP = true; // Configure the fields for a gratuitous ARP packet AutoIPClient.packet.Operation = ARP_OPERATION_REQ; AutoIPClient.packet.TargetMACAddr.v[0] = 0xff; AutoIPClient.packet.TargetMACAddr.v[1] = 0xff; AutoIPClient.packet.TargetMACAddr.v[2] = 0xff; AutoIPClient.packet.TargetMACAddr.v[3] = 0xff; AutoIPClient.packet.TargetMACAddr.v[4] = 0xff; AutoIPClient.packet.TargetMACAddr.v[5] = 0xff; pConfig->MyIPAddr = AutoIPClient.packet.TargetIPAddr; pConfig->MyMask.Val = 0x0000FFFF; memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&pConfig->MyMACAddr, sizeof(AutoIPClient.packet.SenderMACAddr)); AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; AutoIPClient.packet.MACAddrLen = sizeof(MAC_ADDR); AutoIPClient.packet.ProtocolLen = sizeof(IP_ADDR); AutoIPClient.packet.SenderIPAddr.Val = AutoIPClient.packet.TargetIPAddr.Val; SwapARPPacket(&AutoIPClient.packet); // Generate a random delay between 0 and 1 second AutoIPClient.randomDelay = ((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20; // Store the current time AutoIPClient.eventTime = SYS_TICK_Get(); // Set the state to send the ARP packet AutoIPClient.smAUTOIPState = SM_AUTOIP_GRATUITOUS_ARP1; break; // Send a gratuitous ARP packet to try and claim our address case SM_AUTOIP_GRATUITOUS_ARP1: case SM_AUTOIP_GRATUITOUS_ARP2: case SM_AUTOIP_GRATUITOUS_ARP3: // Check to ensure we've passed the delay time if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay) { if(!MACIsTxReady(hMac)) { break; } // Store the new event time AutoIPClient.eventTime = SYS_TICK_Get(); // Generate a new random delay between 1 and 2 seconds AutoIPClient.randomDelay = SYS_TICK_TicksPerSecondGet() + (((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20); // Transmit the packet MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet)); MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(hMac); // Increment the probe iteration or increment to the delay state AutoIPClient.smAUTOIPState++; } break; // Delay for 1-2 seconds after sending the third ARP request before // entering the configured state case SM_AUTOIP_DELAY: if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay) AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; // Configure the module to limit the rate at which packets are sent case SM_AUTOIP_RATE_LIMIT_SET: AutoIPClient.eventTime = SYS_TICK_Get(); pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val; AutoIPClient.smAUTOIPState = SM_AUTOIP_RATE_LIMIT_WAIT; break; // Ensure that we don't try more than one address every 60 seconds case SM_AUTOIP_RATE_LIMIT_WAIT: if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet() * 60) AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; break; // Configured state case SM_AUTOIP_CONFIGURED: AutoIPClient.flags.bits.bConfigureAutoIP = false; break; // Address defense state case SM_AUTOIP_DEFEND: // Prepare and send an ARP response if(!MACIsTxReady(hMac)) { break; } AutoIPClient.packet.Operation = ARP_OPERATION_RESP; AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; SwapARPPacket(&AutoIPClient.packet); MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac)); MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet)); MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(hMac); AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; } } }
void NTPTask(void) { NTP_PACKET pkt; WORD w; switch(NTPState) { case NTP_HOME: debug_ntp(debug_putc, "\r\n\nRefreshing Time\r\n"); // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) break; // Obtain the IP address associated with the server name DNSResolveROM((ROM BYTE*)NTP_SERVER, DNS_TYPE_A); rtcTimer = time(NULL); NTPState = NTP_NAME_RESOLVE; break; case NTP_NAME_RESOLVE: // Wait for DNS resolution to complete if(!DNSIsResolved(&Server.IPAddr)) { if((time(NULL) - rtcTimer) >= NTP_RESOLVE_TIMEOUT) { DNSEndUsage(); rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; } break; } // Obtain DNS resolution result if(!DNSEndUsage()) { // No valid IP address was returned from the DNS // server. Quit and fail for a while if host is not valid. rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; break; } NTPState = NTP_ARP_START_RESOLVE; // No need to break case NTP_ARP_START_RESOLVE: case NTP_ARP_START_RESOLVE2: case NTP_ARP_START_RESOLVE3: // Obtain the MAC address associated with the server's IP address ARPResolve(&Server.IPAddr); rtcTimer = time(NULL); NTPState++; break; case NTP_ARP_RESOLVE: case NTP_ARP_RESOLVE2: case NTP_ARP_RESOLVE3: // Wait for the MAC address to finish being obtained if(!ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) { // Time out if too much time is spent in this state if(time(NULL) - rtcTimer >= NTP_ARP_TIMEOUT) { // Retransmit ARP request by going to next SM_ARP_START_RESOLVE state or fail by going to SM_ARP_RESOLVE_FAIL state. NTPState++; } break; } NTPState = NTP_UDP_SEND; break; case NTP_ARP_RESOLVE_FAIL: // ARP failed after 3 tries, abort and wait for next time query rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; break; case NTP_UDP_SEND: // Open up the sending UDP socket MySocket = UDPOpen(NTP_LOCAL_PORT, &Server, NTP_SERVER_PORT); if(MySocket == INVALID_UDP_SOCKET) break; // Make certain the socket can be written to if(!UDPIsPutReady(MySocket)) { UDPClose(MySocket); break; } // Transmit a time request packet memset(&pkt, 0, sizeof(pkt)); pkt.flags.versionNumber = 3; // NTP Version 3 pkt.flags.mode = 3; // NTP Client pkt.orig_ts_secs = swapl(NTP_EPOCH); UDPPutArray((BYTE*) &pkt, sizeof(pkt)); UDPFlush(); //dwTimer = TickGet(); rtcTimer = time(NULL); NTPState = NTP_UDP_RECV; break; case NTP_UDP_RECV: // Look for a response time packet if(!UDPIsGetReady(MySocket)) { if((time(NULL)) - rtcTimer >= NTP_REPLY_TIMEOUT) { // Abort the request and wait until the next timeout period UDPClose(MySocket); rtcTimer = time(NULL); NTPState = NTP_SHORT_WAIT; break; } break; } // Get the response time packet w = UDPGetArray((BYTE*) &pkt, sizeof(pkt)); UDPClose(MySocket); rtcTimer = time(NULL); // Validate packet size if(w != sizeof(pkt)) { NTPState = NTP_SHORT_WAIT; break; } g_NTPOk = TRUE; NTPState = NTP_WAIT; // Set out local time to match the returned time NTPLastUpdate = swapl(pkt.tx_ts_secs) - NTP_EPOCH; // Do rounding. If the partial seconds is > 0.5 then add 1 to the seconds count. if(((BYTE*)&pkt.tx_ts_fraq)[0] & 0x80) NTPLastUpdate++; SetTimeSec(NTPLastUpdate); break; case NTP_SHORT_WAIT: // Attempt to requery the NTP server after a specified NTP_FAST_QUERY_INTERVAL time (ex: 8 seconds) has elapsed. g_NTPOk = FALSE; if(time(NULL) - rtcTimer >= NTP_WAIT_INTERVAL) NTPState = NTP_HOME; break; case NTP_WAIT: // Requery the NTP server after a specified NTP_QUERY_INTERVAL time (ex: 10 minutes) has elapsed. if(time(NULL) - NTPLastUpdate >= NTP_QUERY_INTERVAL) NTPState = NTP_HOME; break; } }
/***************************************************************************** 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: int recv( SOCKET s, char* buf, int len, int flags ) Summary: The recv() function is used to receive incoming data that has been queued for a socket. Description: The recv() function is used to receive incoming data that has been queued for a socket. This function can be used with both datagram and stream socket. If the available data is too large to fit in the supplied application buffer buf, the data is buffered internally so the application can retreive all data by multiple calls of recv. Precondition: connect function should be called for TCP and UDP sockets. Server side, accept function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data receive buffer. len - buffer length in bytes. flags - no significance in this implementation Returns: If recv is successful, the number of bytes copied to application buffer buf is returned. A value of zero indicates no data available. A return value of SOCKET_ERROR (-1) indicates an error condition. A return value of SOCKET_DISCONNECTED indicates the connection no longer exists. Remarks: None. ***************************************************************************/ int recv( SOCKET s, char* buf, int len, int flags ) { struct BSDSocket *socket; NODE_INFO remoteInfo; static DWORD startTick; if( s >= BSD_SOCKET_COUNT ) return SOCKET_ERROR; socket = &BSDSocketArray[s]; if( socket->bsdState < SKT_BOUND ) return SOCKET_ERROR; if(socket->SocketType == SOCK_STREAM) //TCP { if(!TCPIsConnected(socket->SocketID)) { return SOCKET_DISCONNECTED; } if(TCPIsGetReady(socket->SocketID)) { return TCPGetArray(socket->SocketID, (BYTE*)buf, len); } } else if(socket->SocketType == SOCK_DGRAM) //UDP { if((socket->bsdState >= SKT_READY) && (socket->bsdState != SKT_EST))//making sure that connect function is called { if(socket->bsdState != SKT_ARP_VERIFY) { remoteInfo.IPAddr.Val = socket->remoteIP; ARPResolve(&remoteInfo.IPAddr); startTick = TickGet(); socket->bsdState = SKT_ARP_VERIFY; } else if(socket->bsdState == SKT_ARP_VERIFY) { // Wait for the MAC address to finish being obtained remoteInfo.IPAddr.Val = socket->remoteIP; if(!ARPIsResolved(&remoteInfo.IPAddr, &remoteInfo.MACAddr)) { // Time out if too much time is spent in this state if(TickGet()- startTick > 1*TICK_SECOND) { // Retransmit ARP request socket->bsdState = SKT_ARP_RESOLVE; } } socket->SocketID = UDPOpen(socket->localPort, &remoteInfo, socket->remotePort); socket->bsdState = SKT_EST; } } if(socket->bsdState == SKT_EST) { if(UDPIsGetReady(socket->SocketID) > 0) { return UDPGetArray((BYTE*)buf, len); } } } return 0; }
/***************************************************************************** Function: int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) Summary: This function used to send the data for both connection oriented and connection-less sockets. Description: The sendto function is used to send outgoing data on a socket. The destination address is given by to and tolen. Both Datagram and stream sockets are supported. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data buffer containing data to transmit. len - length of data in bytes. flags - message flags. Currently this field is not supported. to - pointer to the the sockaddr structure containing the destination address. tolen - length of the sockaddr structure. Returns: On success, sendto returns number of bytes sent. In case of error returns SOCKET_ERROR Remarks: None. ***************************************************************************/ int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen ) { struct BSDSocket *socket; struct sockaddr_in *addr; int size=0; NODE_INFO remoteInfo; static DWORD startTick; socket = &BSDSocketArray[s]; addr = (struct sockaddr_in *)to; socket->remotePort = addr->sin_port; socket->remoteIP = addr->sin_addr.s_addr; if(socket->SocketType == SOCK_DGRAM) //UDP { if(socket->bsdState != SKT_EST) { if((addr == NULL) || (addr->sin_addr.s_addr == IP_ADDR_ANY) || (tolen == 0)) //broadcast { socket->SocketID = UDPOpen(socket->localPort, NULL, socket->remotePort); } else { if(socket->bsdState != SKT_ARP_VERIFY) { remoteInfo.IPAddr.Val = socket->remoteIP; ARPResolve(&remoteInfo.IPAddr); startTick = TickGet(); socket->bsdState = SKT_ARP_VERIFY; } else if(socket->bsdState == SKT_ARP_VERIFY) { // Wait for the MAC address to finish being obtained remoteInfo.IPAddr.Val = socket->remoteIP; if(!ARPIsResolved(&remoteInfo.IPAddr, &remoteInfo.MACAddr)) { // Time out if too much time is spent in this state if(TickGet()- startTick > 1*TICK_SECOND) { // Retransmit ARP request socket->bsdState = SKT_ARP_RESOLVE; } } socket->SocketID = UDPOpen(socket->localPort, &remoteInfo, socket->remotePort); socket->bsdState = SKT_EST; } } } if(socket->bsdState == SKT_EST) { if(UDPIsPutReady(socket->SocketID) > 0) { size = UDPPutArray((BYTE*)buf, len); UDPFlush(); return size; } } } else if(socket->SocketType == SOCK_STREAM) //TCP will send to the already established socket. { return send(s, buf, len, 0); } return SOCKET_ERROR; }
/********************************************************************* * Function: void SMTP Client State machine(void) * * PreCondition: FTPInit() must already be called. * * Input: None * * Output: Ready to send mail. * * Side Effects: None * * Overview: * * Note: This function acts as a task (similar to one in * RTOS). This function performs its task in * co-operative manner. Main application must call * this function repeatedly to ensure it can send * mails when requested. (include in the main loop) ********************************************************************/ void SMTPClient(void) { BYTE v; // TICK currentTick; // check if state machine is stuck somewhere and reset the SM after a while if needed : if ((smSMTP != SM_SMTP_STDBY) && (TickGetDiff(TickGet(), lastActivity) > (15 * TICK_SECOND))) { if (TCPIsConnected(SMTPSocket)) TCPDisconnect(SMTPSocket) ; if(cptretry--) { // if not all retries done... lastActivity = TickGet(); // re-init delay smSMTP = SM_SMTP_STDBY ; // force standby state } else { fsend_mail = FALSE ; // give up ! smSMTP = SM_SMTP_STDBY ; // -> standby } } // work each state : switch(smSMTP) { case SM_SMTP_STDBY: // standby: idle, waiting for connection request if (fsend_mail) { if (TickGetDiff(TickGet(), lastActivity) > (10 * TICK_SECOND)) { USARTPut(0xBB) ; lastActivity = TickGet(); ARPResolve(&nodedist.IPAddr) ; // resolve IP adress smSMTP = SM_SMTP_ARP ; // -> wait ARP answer } } break ; case SM_SMTP_ARP: // wait ARP to be resolved if ( ARPIsResolved(&nodedist.IPAddr, &nodedist.MACAddr)) { SMTPSocket = TCPConnect(&nodedist, SMTP_PORT) ; if (SMTPSocket == INVALID_SOCKET) { fsend_mail = FALSE ; // avorte } else { smSMTP = SM_SMTP_CONNECT ; // -> attente ACK } } break ; case SM_SMTP_CONNECT: // standby: attente ack connexion if (TCPIsConnected(SMTPSocket)) { smSMTP = SM_SMTP_WELCOME ; // -> attente WELCOME } break ; case SM_SMTP_WELCOME: // attente welcome du serveur if (TCPIsGetReady(SMTPSocket)) { if (TCPGet(SMTPSocket, &v)) { if (v == '2') { // commence par un 2 ? (220..) TCPDiscard(SMTPSocket) ; ExecuteSMTPCommand(SMTP_CMD_HELO) ; smSMTP = SM_SMTP_HELO ; // -> attente reponse au HELO }else { smSMTP = SM_SMTP_DONE ; // -> disconnect } } } break ; case SM_SMTP_HELO: // attente HELO du serveur if (TCPIsGetReady(SMTPSocket)) { if (TCPGet(SMTPSocket,&v)) { if (v == '2') { // commence par un 2 ? (220..) TCPDiscard(SMTPSocket) ; ExecuteSMTPCommand(SMTP_CMD_FROM) ; smSMTP = SM_SMTP_FROM ; // -> attente reponse au FROM }else { smSMTP = SM_SMTP_DONE ; // -> disconnect } } } break ; case SM_SMTP_FROM: // attente HELO du serveur if (TCPIsGetReady(SMTPSocket)) { if (TCPGet(SMTPSocket,&v)) { if (v == '2') { // commence par un 2 ? (220..) TCPDiscard(SMTPSocket) ; ExecuteSMTPCommand(SMTP_CMD_TO) ; smSMTP = SM_SMTP_TO ; // -> attente reponse au TO }else { smSMTP = SM_SMTP_DONE ; // -> disconnect } } } break ; case SM_SMTP_TO: // attente HELO du serveur if (TCPIsGetReady(SMTPSocket)) { if (TCPGet(SMTPSocket,&v)) { if (v == '2') { // commence par un 2 ? (220..) TCPDiscard(SMTPSocket) ; ExecuteSMTPCommand(SMTP_CMD_DATA) ; smSMTP = SM_SMTP_DATA1 ; // -> attente reponse au DATA }else { smSMTP = SM_SMTP_DONE ; // -> disconnect } } } break ; case SM_SMTP_DATA1: // when OK send message headers if (TCPIsGetReady(SMTPSocket)) { if (TCPGet(SMTPSocket,&v)) { if (v == '3') { // commence par un 3 ? (220..) TCPDiscard(SMTPSocket) ; ExecuteSMTPCommand(SMTP_CMD_DATA_HEADERS) ; // send headers // ExecuteSMTPCommand(SMTP_CMD_DATA_MESSAGE) ; // message // ExecuteSMTPCommand(SMTP_CMD_DATA_END) ; // termine smSMTP = SM_SMTP_DATA2; // -> send body }else { smSMTP = SM_SMTP_DONE ; // -> disconnect } } } break ; case SM_SMTP_DATA2: // wait to send message body if (TCPIsPutReady(SMTPSocket)) { // wait for TX buffer free ExecuteSMTPCommand(SMTP_CMD_DATA_MESSAGE) ; // message smSMTP = SM_SMTP_DATA3 ; // -> attente reponse au TO } else { // USARTPut(0xCC) ; vérifié qu'il y avait bien besoin d'une attente ici } break ; case SM_SMTP_DATA3: // wait to send the final "." if (TCPIsPutReady(SMTPSocket)) { // wait for TX buffer free ExecuteSMTPCommand(SMTP_CMD_DATA_END) ; // termine smSMTP = SM_SMTP_QUIT ; // -> end } else { // USARTPut(0xDD) ; vérifié qu'il y avait bien besoin d'une attente ici } break ; case SM_SMTP_QUIT: // wait last message before leaving... if (TCPIsGetReady(SMTPSocket)) { if (TCPGet(SMTPSocket,&v)) { if (v == '2') { // commence par un 2 ? (220..) TCPDiscard(SMTPSocket) ; smSMTP = SM_SMTP_DONE ; // -> deconnecte }else { smSMTP = SM_SMTP_DONE ; // -> disconnect } } } break ; case SM_SMTP_DONE: // disconnect Socket : if (TCPIsConnected(SMTPSocket) && (TCPIsPutReady(SMTPSocket))) { // wait for TX buff free TCPDisconnect(SMTPSocket) ; } fsend_mail = FALSE ; // done ! smSMTP = SM_SMTP_STDBY ; // -> standby break ; } }
void lftp_task( void ) { WORD ttt; BYTE c; BOOL bPreLine; BOOL bPostLine; // Nothing to do if we don't have a link if ( !MACIsLinked() ) return; // check if state machine is stuck somewhere and reset the it after a while if needed : if ( ( ftp_state != LFTP_STATE_NONE ) && ( TickGetDiff( TickGet(), lastActivity) > ( LFTP_TIMEOUT * TICK_SECOND ) ) ) { // Close ftp client socker if open //if ( TCPIsConnected( ftpsocket ) ) { writeRomString2Socket( quit ); TCPDisconnect( ftpsocket ); ftpsocket = UNKNOWN_SOCKET; //} // Close data socket if open TCPDisconnect( datasocket ); datasocket = UNKNOWN_SOCKET; // Check if we should try again or if its time // to pack it in cntBeforeFail++; if ( cntBeforeFail > LFTP_MAX_RETRIES ) { cntBeforeFail = 0; ftp_state = LFTP_STATE_NONE; // Give up... bftpLoadWork = FALSE; // Work is done - failed } ftp_state = LFTP_STATE_NONE; } switch( ftp_state ) { // ** // Start to work if its time to do so case LFTP_STATE_NONE: // Check timer and see if we should fetch // data from the server. lastActivity = TickGet(); if ( bftpLoadWork ) { ftp_state = LFTP_STATE_ARP; // Must get MAC address for server cntBeforeFail = 0; // Init. failure counter DBG_OUT('A'); } break; //** // Resolve the MAC address of the ftp server case LFTP_STATE_ARP: ftp_nodeinfo.IPAddr.v[ 0 ] = LFTP_SERVER_IP_v0; ftp_nodeinfo.IPAddr.v[ 1 ] = LFTP_SERVER_IP_v1; ftp_nodeinfo.IPAddr.v[ 2 ] = LFTP_SERVER_IP_v2; ftp_nodeinfo.IPAddr.v[ 3 ] = LFTP_SERVER_IP_v3; if ( ARPIsTxReady() ) { DBG_OUT('B'); ARPResolve( &ftp_nodeinfo.IPAddr ); // resolve IP adress ftp_state = LFTP_STATE_ARP_RESOLVE; lastActivity = TickGet(); } break; // ** // Check if the ftp MAC address is resolved case LFTP_STATE_ARP_RESOLVE: if ( ARPIsResolved( &ftp_nodeinfo.IPAddr, &ftp_nodeinfo.MACAddr ) ) { DBG_OUT('D'); ftp_state = LFTP_STATE_CONNECT; lastActivity = TickGet(); } break; // ** // Connect to ftp server case LFTP_STATE_CONNECT: // Try to connect ftpsocket = TCPConnect( &ftp_nodeinfo, LFTP_PORT ); if ( INVALID_SOCKET != ftpsocket ) { DBG_OUT('E'); ftp_state = LFTP_STATE_CONNECT_WAIT; lastActivity = TickGet(); } break; // ** // Waiting for ftp connection case LFTP_STATE_CONNECT_WAIT: if ( TCPIsConnected( ftpsocket ) ) { DBG_OUT('F'); ftp_state = LFTP_STATE_USER; lastActivity = TickGet(); } break; // Here we wait for server connection and send // USER command if OK case LFTP_STATE_USER: // Fetch data if we are connected if ( TCPIsGetReady( ftpsocket ) ) { // get first digit while( TCPGet( ftpsocket, &c ) ) { if ( isdigit( c ) ) break; } // If connected with positive response "2xx - xxxxxxxx..." // we send username. If not we just timeout if ( '2' == c ) { DBG_OUT('G'); writeRomString2Socket( user ); ftp_state = LFTP_STATE_PASS; lastActivity = TickGet(); } TCPDiscard( ftpsocket ); } break; // ** // Here we wait for response from USER command // and send PASS command if OK case LFTP_STATE_PASS: // Fetch data if we are connected if ( TCPIsGetReady( ftpsocket ) ) { DBG_OUT('$'); // get first digit while( TCPGet( ftpsocket, &c ) ) { DBG_OUT(c); if ( isdigit( c ) ) break; } // If connected with positive response "3xx - xxxxxxxx..." // we send username. If not we just timeout if ( ('3' == c ) || ('2' == c ) ) { DBG_OUT('H'); writeRomString2Socket( pass ); ftp_state = LFTP_STATE_PASV; lastActivity = TickGet(); } TCPDiscard( ftpsocket ); } break; // ** // Here we wait for response of PASS command // and send PASV command if positive and also // creates the data socket case LFTP_STATE_PASV: // Fetch data if we are connected if ( TCPIsGetReady( ftpsocket ) ) { DBG_OUT('!'); // get first digit while( TCPGet( ftpsocket, &c ) ) { DBG_OUT(c); if ( isdigit( c ) ) break; } // If connected with positive response "2xx - xxxxxxxx..." // we send username. If not we just timeout if ( '2' == c ) { DBG_OUT('I'); writeRomString2Socket( pasv ); ftp_state = LFTP_STATE_RETR; lastActivity = TickGet(); } TCPDiscard( ftpsocket ); } break; // ** // Here we wait for the result of PASV command // and parse its data // if OK we send RETR and go on to the next state case LFTP_STATE_RETR: // Fetch data if we are connected if ( TCPIsGetReady( ftpsocket ) ) { TCPGet( ftpsocket, &c ); if ( '2' == c ) { DBG_OUT('J'); // Get pasv parameters getPasvParams(); // retrive file writeRomString2Socket( retr ); ttt = portdata; while ( ttt ) { DBG_OUT('0' + (ttt % 10) ); ttt = ttt / 10; } ftp_state = LFTP_STATE_DATA_CONNECT; } TCPDiscard( ftpsocket ); } break; // ** // Connect to the data socket case LFTP_STATE_DATA_CONNECT: // Try to connect datasocket = TCPConnect( &ftp_nodeinfo, portdata ); if ( INVALID_SOCKET != datasocket ) { DBG_OUT('K'); ftp_state = LFTP_STATE_WAIT_DATA_CONNECT; lastActivity = TickGet(); } break; // ** // Wait for the data connection to establish case LFTP_STATE_WAIT_DATA_CONNECT: if ( TCPIsConnected( datasocket ) ) { DBG_OUT('L'); //writeRomString2Socket( lftpDataSocket, crlf ); ftp_state = LFTP_STATE_FETCH_DATA; lastActivity = TickGet(); } // Check for reply on ftp socket FIX!!!! if ( TCPIsGetReady( ftpsocket ) ) { DBG_OUT('?'); while( TCPGet( ftpsocket, &c ) ) { DBG_OUT( c ); } TCPDiscard( ftpsocket ); } break; // ** // Fetch the data and send it out on the // serial i/f case LFTP_STATE_FETCH_DATA: // Fetch data if we are connected if ( TCPIsGetReady( datasocket ) ) { DBG_OUT('M'); // Framework start serPutByte( 0x00 ); serPutByte( 0xff ); serPutByte( 0xff ); serPutByte( 0x01 ); serPutByte( 0x01 ); serPutByte( 0x01 ); bPreLine = FALSE; bPostLine = FALSE; // get data while( TCPGet( datasocket, &c ) ) { if ( 0x0d == c ) { // We skip CR } else if ( 0x0a == c ) { // Send end line stuff serPutByte( 0xff ); bPreLine = FALSE; bPostLine = TRUE; } else { bPostLine = FALSE; // no end line codes sent if ( !bPreLine ) { // Send preline stuff bPreLine = TRUE; serPutByte( 0x01 ); serPutByte( 0x03 ); serPutByte( 0xef ); serPutByte( 0xb0 ); } serPutByte( c ); } } // If we end with a row without LF we must send // Line end stuff if ( !bPostLine ) { serPutByte( 0xff ); } // Framework end serPutByte( 0xff ); serPutByte( 0x00 ); ftp_state = LFTP_STATE_END; TCPDiscard( datasocket ); } // Check for data on ftp socket if ( TCPIsGetReady( ftpsocket ) ) { while( TCPGet( ftpsocket, &c ) ) { DBG_OUT( c ); } TCPDiscard( ftpsocket ); } break; // ** // We are done for this time case LFTP_STATE_END: DBG_OUT('*'); TCPDisconnect( ftpsocket ); TCPDisconnect( datasocket ); bftpLoadWork = FALSE; // Work is done ftp_state = LFTP_STATE_NONE; break; } }
void AutoIPTasks(void) { BYTE i; for (i = 0; i < NETWORK_INTERFACES; i++) { LoadState (i); AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(); if(AutoIPClient.flags.bits.bCurrentLinkState != AutoIPClient.flags.bits.bLastLinkState) { AutoIPClient.flags.bits.bLastLinkState = AutoIPClient.flags.bits.bCurrentLinkState; if(!AutoIPClient.flags.bits.bCurrentLinkState) { AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AppConfig.MyIPAddr.Val = AppConfig.DefaultIPAddr.Val; AppConfig.MyMask.Val = AppConfig.DefaultMask.Val; } else { AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } } #if defined (STACK_USE_DHCP_CLIENT) if (DHCPIsBound(i)) { AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; AutoIPClient.flags.bits.bLastDHCPState = TRUE; } else { if (AutoIPClient.flags.bits.bLastDHCPState == TRUE) { if (AutoIPClient.flags.bits.bCurrentLinkState) AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG; } AutoIPClient.flags.bits.bLastDHCPState = FALSE; } #endif if (AutoIPClient.flags.bits.gDisableAutoIP == TRUE) { AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED; } switch (AutoIPClient.smAUTOIPState) { // Default no-AutoIP case case SM_AUTOIP_DISABLED: break; // Initializes the random number generator with a seed based on the MAC address case SM_AUTOIP_INIT_RNG: AutoIPRandSeed (((DWORD)AppConfig.MyMACAddr.v[0] + ((DWORD)AppConfig.MyMACAddr.v[1] << 8) + \ ((DWORD)AppConfig.MyMACAddr.v[2] << 16) + ((DWORD)AppConfig.MyMACAddr.v[3] << 24) + \ ((DWORD)AppConfig.MyMACAddr.v[4]) + ((DWORD)AppConfig.MyMACAddr.v[5] << 8)), i); AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; // Check the address to see if it's in use before we write it into AppConfig case SM_AUTOIP_CHECK_ADDRESS: if (AutoIPClient.flags.bits.checkAddress == FALSE) { AutoIPClient.flags.bits.checkAddress = TRUE; AppConfig.MyMask.Val = 0x00000000; // Generate a random IP address (based on the MAC address) to try and claim. // Dynamic link-local addresses can fall within the range: // 169.254.1.0 - 169.254.254.255 AutoIPClient.packet.TargetIPAddr.byte.MB = AutoIPRand(i) % 256; AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(i) % 254) + 1; AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9; ARPResolve (&AutoIPClient.packet.TargetIPAddr); AutoIPClient.eventTime = TickGet(); } if (!ARPIsResolved (&AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr)) { if (TickGet() - AutoIPClient.eventTime > TICK_SECOND) { AutoIPClient.smAUTOIPState = SM_AUTOIP_SETUP_MESSAGE; } } else { AutoIPClient.flags.bits.checkAddress = FALSE; } break; // Set up an ARP packet case SM_AUTOIP_SETUP_MESSAGE: AutoIPClient.flags.bits.checkAddress = FALSE; // Set the bConfigureAutoIP flag- This flag will cause an AutoIP conflict // if a response packet is received from the address we're trying to claim. AutoIPClient.flags.bits.bConfigureAutoIP = TRUE; // Configure the fields for a gratuitous ARP packet AutoIPClient.packet.Operation = ARP_OPERATION_REQ; AutoIPClient.packet.TargetMACAddr.v[0] = 0xff; AutoIPClient.packet.TargetMACAddr.v[1] = 0xff; AutoIPClient.packet.TargetMACAddr.v[2] = 0xff; AutoIPClient.packet.TargetMACAddr.v[3] = 0xff; AutoIPClient.packet.TargetMACAddr.v[4] = 0xff; AutoIPClient.packet.TargetMACAddr.v[5] = 0xff; AppConfig.MyIPAddr = AutoIPClient.packet.TargetIPAddr; AppConfig.MyMask.Val = 0x0000FFFF; memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&AppConfig.MyMACAddr, sizeof(AutoIPClient.packet.SenderMACAddr)); AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; AutoIPClient.packet.MACAddrLen = sizeof(MAC_ADDR); AutoIPClient.packet.ProtocolLen = sizeof(IP_ADDR); AutoIPClient.packet.SenderIPAddr.Val = AutoIPClient.packet.TargetIPAddr.Val; SwapARPPacket(&AutoIPClient.packet); // Generate a random delay between 0 and 1 second AutoIPClient.randomDelay = ((rand() % 20) * TICK_SECOND) / 20; // Store the current time AutoIPClient.eventTime = TickGet(); // Set the state to send the ARP packet AutoIPClient.smAUTOIPState = SM_AUTOIP_GRATUITOUS_ARP1; break; // Send a gratuitous ARP packet to try and claim our address case SM_AUTOIP_GRATUITOUS_ARP1: case SM_AUTOIP_GRATUITOUS_ARP2: case SM_AUTOIP_GRATUITOUS_ARP3: // Check to ensure we've passed the delay time if (TickGet() - AutoIPClient.eventTime > AutoIPClient.randomDelay) { // Store the new event time AutoIPClient.eventTime = TickGet(); // Generate a new random delay between 1 and 2 seconds AutoIPClient.randomDelay = TICK_SECOND + (((rand() % 20) * TICK_SECOND) / 20); // Transmit the packet while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); MACPutHeader(&AutoIPClient.packet.TargetMACAddr, MAC_ARP, sizeof(AutoIPClient.packet)); MACPutArray((BYTE*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(); // Increment the probe iteration or increment to the delay state AutoIPClient.smAUTOIPState++; } break; // Delay for 1-2 seconds after sending the third ARP request before // entering the configured state case SM_AUTOIP_DELAY: if (TickGet() - AutoIPClient.eventTime > AutoIPClient.randomDelay) AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; // Configure the module to limit the rate at which packets are sent case SM_AUTOIP_RATE_LIMIT_SET: AutoIPClient.eventTime = TickGet(); AppConfig.MyIPAddr.v[0] = MY_DEFAULT_IP_ADDR_BYTE1; AppConfig.MyIPAddr.v[1] = MY_DEFAULT_IP_ADDR_BYTE2; AppConfig.MyIPAddr.v[2] = MY_DEFAULT_IP_ADDR_BYTE3; AppConfig.MyIPAddr.v[3] = MY_DEFAULT_IP_ADDR_BYTE4; AutoIPClient.smAUTOIPState = SM_AUTOIP_RATE_LIMIT_WAIT; break; // Ensure that we don't try more than one address every 60 seconds case SM_AUTOIP_RATE_LIMIT_WAIT: if (TickGet() - AutoIPClient.eventTime > TICK_SECOND * 60) AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS; break; // Configured state case SM_AUTOIP_CONFIGURED: AutoIPClient.flags.bits.bConfigureAutoIP = FALSE; break; // Address defense state case SM_AUTOIP_DEFEND: // Prepare and send an ARP response AutoIPClient.packet.Operation = ARP_OPERATION_RESP; AutoIPClient.packet.HardwareType = HW_ETHERNET; AutoIPClient.packet.Protocol = ARP_IP; SwapARPPacket(&AutoIPClient.packet); while(!MACIsTxReady()); MACSetWritePtr(BASE_TX_ADDR); MACPutHeader(&AutoIPClient.packet.TargetMACAddr, MAC_ARP, sizeof(AutoIPClient.packet)); MACPutArray((BYTE*)&AutoIPClient.packet, sizeof(AutoIPClient.packet)); MACFlush(); AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED; break; } } }
/***************************************************************************** Function: int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) Summary: This function used to send the data for both connection oriented and connection-less sockets. Description: The sendto function is used to send outgoing data on a socket. The destination address is given by to and tolen. Both Datagram and stream sockets are supported. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data buffer containing data to transmit. len - length of data in bytes. flags - message flags. Currently this field is not supported. to - Optional pointer to the the sockaddr structure containing the destination address. If NULL, the currently bound remote port and IP address are used as the destination. tolen - length of the sockaddr structure. Returns: On success, sendto returns number of bytes sent. In case of error returns SOCKET_ERROR Remarks: None. ***************************************************************************/ int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen ) { struct BSDSocket *socket; int size = SOCKET_ERROR; NODE_INFO remoteInfo; // static DWORD startTick; // NOTE: startTick really should be a per socket BSDSocket structure member since other BSD calls can interfere with the ARP cycles WORD wRemotePort; struct sockaddr_in local; if( s >= BSD_SOCKET_COUNT ) return SOCKET_ERROR; socket = &BSDSocketArray[s]; if(socket->bsdState == SKT_CLOSED) return SOCKET_ERROR; if(socket->SocketType == SOCK_DGRAM) //UDP { // Decide the destination IP address and port remoteInfo.IPAddr.Val = socket->remoteIP; wRemotePort = socket->remotePort; if(to) { if((unsigned int)tolen != sizeof(struct sockaddr_in)) return SOCKET_ERROR; wRemotePort = ((struct sockaddr_in*)to)->sin_port; remoteInfo.IPAddr.Val = ((struct sockaddr_in*)to)->sin_addr.s_addr; // Implicitly bind the socket if it isn't already if(socket->bsdState == SKT_CREATED) { memset(&local, 0x00, sizeof(local)); if(bind(s, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) return SOCKET_ERROR; } } if(UDPIsOpened((UDP_SOCKET)s) != TRUE) return SOCKET_ERROR; if(remoteInfo.IPAddr.Val == IP_ADDR_ANY) remoteInfo.IPAddr.Val = 0xFFFFFFFFu; #if 0 // Set the remote IP and MAC address if it is different from what we already have stored in the UDP socket if(UDPSocketInfo[socket->SocketID].remoteNode.IPAddr.Val != remoteInfo.IPAddr.Val) { if(ARPIsResolved(&remoteInfo.IPAddr, &remoteInfo.MACAddr)) { memcpy((void*)&UDPSocketInfo[socket->SocketID].remoteNode, (void*)&remoteInfo, sizeof(remoteInfo)); } else { if(TickGet() - startTick > 1*TICK_SECOND) { ARPResolve(&remoteInfo.IPAddr); startTick = TickGet(); } return SOCKET_ERROR; } } #endif // Select the UDP socket and see if we can write to it if(UDPIsPutReady(socket->SocketID)) { // Set the proper remote port UDPSocketInfo[socket->SocketID].remotePort = wRemotePort; // Write data and send UDP datagram size = UDPPutArray((BYTE*)buf, len); UDPFlush(); return size; } } else if(socket->SocketType == SOCK_STREAM) //TCP will only send to the already established socket. { if(socket->bsdState != SKT_EST) return SOCKET_ERROR; if(HandlePossibleTCPDisconnection(s)) return SOCKET_ERROR; // Handle special case were 0 return value is okay if(len == 0) return 0; // Write data to the socket. If one or more bytes were written, then // return this value. Otherwise, fail and return SOCKET_ERROR. size = TCPPutArray(socket->SocketID, (BYTE*)buf, len); if(size) return size; } return SOCKET_ERROR; }
/***************************************************************************** Function: void PingDemoTask (void) Summary: Handles state machine for ping demo processes. Description: This function performs state processing for the ping demo. This function can be used as a model for applications requiring Ping6 capabilities to check if a host is reachable. Precondition: None. Parameters: None Returns: None ***************************************************************************/ void PingDemoTask (void) { switch (pingState) { #if defined (TCPIP_STACK_USE_ICMP_CLIENT) case STATE_DNS_SEND_QUERY_IPV4: if (!DNSBeginUsage(pNetIf)) return; if (DNSResolve((const char *)targetHostName, DNS_TYPE_A) != DNS_RES_OK) return; pingTimer = SYS_TICK_Get() + (SYS_TICK_ResolutionGet() * TCPIP_PING_DNS_TIMEOUT); pingState = STATE_DNS_GET_RESPONSE_IPV4; break; case STATE_DNS_GET_RESPONSE_IPV4: { DNS_RESULT res; if ((long)(SYS_TICK_Get() - pingTimer) > 0) { SYS_OUT_MESSAGE_LINE("Couldn't resolve", 2); DNSEndUsage(pNetIf); pingState = STATE_IDLE; return; } res = DNSIsResolved((const char *)targetHostName, &targetAddressIPv4); switch (res) { case DNS_RES_OK: DNSEndUsage(pNetIf); pingState = STATE_RESOLVE_ARP; break; case DNS_RES_PENDING: break; default: SYS_OUT_MESSAGE_LINE ("Couldn't resolve", 1); DNSEndUsage(pNetIf); pingState = STATE_IDLE; break; } } break; case STATE_RESOLVE_ARP: if ((targetAddressIPv4.Val & pNetIf->MyMask.Val) == pNetIf->MyMask.Val) firstHopAddress.Val = targetAddressIPv4.Val; else firstHopAddress.Val = pNetIf->MyGateway.Val; ARPResolve(pNetIf, &firstHopAddress); pingTimer = SYS_TICK_Get(); pingState = STATE_ARP_RESOLVED; break; case STATE_ARP_RESOLVED: if(!ARPIsResolved(pNetIf, &firstHopAddress, &targetMACAddr)) { if(SYS_TICK_Get() - pingTimer > (TCPIP_PING_DNS_TIMEOUT * SYS_TICK_TicksPerSecondGet())) { SYS_OUT_MESSAGE_LINE ("Couldn't ARP", 1); pingState = STATE_IDLE; } break; } pingState = STATE_SEND_ECHO_REQUEST_IPV4; break; #endif #if defined (TCPIP_STACK_USE_IPV6) case STATE_DNS_SEND_QUERY_IPV6: if (!DNSBeginUsage(pNetIf)) return; if (DNSResolve((const char *)targetHostName, DNS_TYPE_AAAA) != DNS_RES_OK) return; pingTimer = SYS_TICK_Get() + (SYS_TICK_ResolutionGet() * TCPIP_PING_DNS_TIMEOUT); pingState = STATE_DNS_GET_RESPONSE_IPV6; break; case STATE_DNS_GET_RESPONSE_IPV6: { DNS_RESULT res; if ((long)(SYS_TICK_Get() - pingTimer) > 0) { SYS_OUT_MESSAGE_LINE ("Couldn't resolve", 1); DNSEndUsage(pNetIf); pingState = STATE_IDLE; return; } res = DNSIsResolved((const char *)targetHostName, &targetAddressIPv6); switch (res) { case DNS_RES_OK: DNSEndUsage(pNetIf); pingState = STATE_SEND_ECHO_REQUEST_IPV6; break; case DNS_RES_PENDING: break; default: SYS_OUT_MESSAGE_LINE ("Couldn't resolve", 1); DNSEndUsage(pNetIf); pingState = STATE_IDLE; break; } } break; #endif #if defined(TCPIP_STACK_USE_ICMP_CLIENT) case STATE_SEND_ECHO_REQUEST_IPV4: { NODE_INFO info; info.IPAddr = targetAddressIPv4; memcpy (&info.MACAddr, &targetMACAddr, sizeof (MAC_ADDR)); ICMPSendEchoRequest (&info, ++wICMPSequenceNumber, 0xBEEF); // Record the current time. This will be used as a basis for // finding the echo response time, which exludes the ARP and DNS // steps pingTimer = SYS_TICK_Get(); pingCount++; SYS_OUT_MESSAGE_LINE ("Pinging...", 1); // Echo sent, advance state pingState = STATE_GET_RESPONSE_IPV4; } break; #endif #if defined (TCPIP_STACK_USE_IPV6) case STATE_SEND_ECHO_REQUEST_IPV6: { IP_PACKET * pkt; IPV6_ADDR_STRUCT * localAddress; localAddress = TCPIP_IPV6_DAS_SelectSourceAddress (pNetIf, &targetAddressIPv6, NULL); if (localAddress == NULL) { SYS_OUT_MESSAGE_LINE ("No local addr!", 1); pingState = STATE_IDLE; break; } pkt = TCPIP_ICMPV6_PutHeaderEchoRequest (pNetIf, &localAddress->address, &targetAddressIPv6, ICMPV6_INFO_ECHO_REQUEST, 0xEFBE, ++wICMPSequenceNumber); if (TCPIP_IP_IsTxPutReady(pkt, 4) < 4) { TCPIP_IP_FreePacket (pkt); return; } TCPIP_IP_PutArray (pkt, (uint8_t *)&miscData, sizeof (uint32_t)); // Just let the IPv6 module figure out the next hop neighbor and its MAC address TCPIP_ICMPV6_Flush (pkt); // Record the current time. This will be used as a basis for // finding the echo response time, which exludes the ARP and DNS // steps pingTimer = SYS_TICK_Get(); pingCount++; SYS_OUT_MESSAGE_LINE ("Pinging...", 1); // Echo sent, advance state pingState = STATE_GET_RESPONSE_IPV6; } break; #endif #if defined (TCPIP_STACK_USE_ICMP_CLIENT) case STATE_GET_RESPONSE_IPV4: if ((long)(SYS_TICK_Get() - pingTimer) > (SYS_TICK_ResolutionGet() * TCPIP_PING_TIMEOUT)) { SYS_OUT_MESSAGE_LINE("Ping timeout", 1); pingState = STATE_IDLE; } break; #endif #if defined (TCPIP_STACK_USE_IPV6) case STATE_GET_RESPONSE_IPV6: if ((long)(SYS_TICK_Get() - pingTimer) > (SYS_TICK_ResolutionGet() * TCPIP_PING_TIMEOUT)) { SYS_OUT_MESSAGE_LINE ("Ping timeout", 1); pingState = STATE_IDLE; } break; #endif default: case STATE_IDLE: break; } }
/* * Main entry point. */ void main(void) { TICK8 tsecWait = 0; //General purpose wait timer TICK16 tsecMsgSent = 0; //Time last message was sent TICK16 tsecBlinker = 0; BYTE main_state; // what are the inputs BYTE main_inputs; // who has the transmit char c; NODE_INFO udpServerNode; //Initialize AppConfig structure appcfgInit(); //Initialize any application specific hardware. InitializeBoard(); //Initialize all stack related components. TickInit(); //Initialize the TCP/IP stack StackInit(); ///////////////////////////////////////////////// //Initialize UDP socket //Initialize remote IP and address with 10.1.0.101. The MAC address is //is not intialized yet, but after we receive an ARP responce. //Configure for local port 54123 and remote port 54124. udpServerNode.IPAddr.v[0] = 255; udpServerNode.IPAddr.v[1] = 255; udpServerNode.IPAddr.v[2] = 255; udpServerNode.IPAddr.v[3] = 255; udpSocketUser = UDPOpen(54123, &udpServerNode, 54124); //udpSocketUser = UDPOpen(54123, NULL, 54124); smUdp = SM_UDP_RESOLVED; //An error occurred during the UDPOpen() function if (udpSocketUser == INVALID_UDP_SOCKET) { //Add user code here to take action if required! } /* * Once all items are initialized, go into infinite loop and let stack items execute * their tasks. If the application needs to perform its own task, it should be done at * the end of while loop. Note that this is a "co-operative mult-tasking" mechanism where * every task performs its tasks (whether all in one shot or part of it) and returns so * that other tasks can do their job. If a task needs very long time to do its job, it * must broken down into smaller pieces so that other tasks can have CPU time. */ while(1) { ServiceBoard(); if (TickGetSecDiff(tsecBlinker) >= (TICK16)1) { tsecBlinker = TickGetSec(); //Update with current time //Toggle system LED #ifdef BLINKTIME TRISB_RB6 = 0; LATB6 ^= 1; #endif } switch (smUdp) { case SM_UDP_SEND_ARP: if (ARPIsTxReady()) { tsecWait = TickGet8bitSec(); //Remember when we sent last request //Send ARP request for given IP address ARPResolve(&udpServerNode.IPAddr); smUdp = SM_UDP_WAIT_RESOLVE; } break; case SM_UDP_WAIT_RESOLVE: //The IP address has been resolved, we now have the MAC address of the //node at 10.1.0.101 if (ARPIsResolved(&udpServerNode.IPAddr, &udpServerNode.MACAddr)) { smUdp = SM_UDP_RESOLVED; } //If not resolved after 2 seconds, send next request else { if (TickGetDiff8bitSec(tsecWait) >= (TICK8)2) { smUdp = SM_UDP_SEND_ARP; } } break; case SM_UDP_RESOLVED: if ( 1 || !PORTB_RB0) { //Send a message every second for as long as PIC port pin B0 is = 0 if ((TickGetSecDiff(tsecMsgSent) >= (TICK16)1) || ((main_state != old_state) || (main_inputs != old_inputs))) { //Checks if there is a transmit buffer ready for accepting data, and that the given socket //is valid (not equal to INVALID_UDP_SOCKET for example) if (UDPIsPutReady(udpSocketUser)) { tsecMsgSent = TickGetSec(); //Update with current time //Send a UDP Datagram with one byte only indicating the status We are only interrested in the first byte of the message. UDPPut('H');UDPPut('E');UDPPut('L');UDPPut('L');UDPPut('O'); UDPPut(old_state); UDPPut(old_inputs); main_state = old_state; main_inputs = old_inputs; //Send contents of transmit buffer, and free buffer UDPFlush(); //Toggle system LED each time a message is sent TRISB_RB6 = 0; LATB6 ^= 1; } } } break; } //This task performs normal stack task including checking for incoming packet, //type of packet and calling appropriate stack entity to process it. StackTask(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // ADD USER CODE HERE //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } }
/***************************************************************************** Function: int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) Summary: This function used to send the data for both connection oriented and connection-less sockets. Description: The sendto function is used to send outgoing data on a socket. The destination address is given by to and tolen. Both Datagram and stream sockets are supported. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. buf - application data buffer containing data to transmit. len - length of data in bytes. flags - message flags. Currently this field is not supported. to - Optional pointer to the the sockaddr structure containing the destination address. If NULL, the currently bound remote port and IP address are used as the destination. tolen - length of the sockaddr structure. Returns: On success, sendto returns number of bytes sent. In case of error returns SOCKET_ERROR (and errno set accordingly). Remarks: None. ***************************************************************************/ int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen ) { struct BSDSocket *socket; UDP_SOCKET_DCPT* udpSkt; int size = SOCKET_ERROR; NODE_INFO remoteInfo; uint16_t wRemotePort; struct sockaddr_in local; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } socket = &BSDSocketArray[s]; if(socket->bsdState == SKT_CLOSED) { errno = EBADF; return SOCKET_ERROR; } if(socket->SocketType == SOCK_DGRAM) //UDP { // Decide the destination IP address and port remoteInfo.IPAddr.Val = socket->remoteIP; wRemotePort = socket->remotePort; if(to) { if((unsigned int)tolen != sizeof(struct sockaddr_in)) { errno = EFAULT; return SOCKET_ERROR; } wRemotePort = ((struct sockaddr_in*)to)->sin_port; remoteInfo.IPAddr.Val = ((struct sockaddr_in*)to)->sin_addr.s_addr; // Implicitly bind the socket if it isn't already if(socket->bsdState == SKT_CREATED) { memset(&local, 0x00, sizeof(local)); if(bind(s, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) return SOCKET_ERROR; } } if(remoteInfo.IPAddr.Val == IP_ADDR_ANY) remoteInfo.IPAddr.Val = 0xFFFFFFFFu; // Set the remote IP and MAC address if it is different from what we already have stored in the UDP socket udpSkt = UDPSocketDcpt + socket->SocketID; if(TCPIP_IPV4_GetDestAddress(udpSkt->pTxPkt).Val != remoteInfo.IPAddr.Val) { TCPIP_IPV4_SetDestAddress(udpSkt->pTxPkt, remoteInfo.IPAddr.Val); if(!ARPIsResolved(UDPSocketGetNet(socket->SocketID), &remoteInfo.IPAddr, &((IPV4_PACKET*)udpSkt->pTxPkt)->remoteMACAddr)) { errno = EINPROGRESS; return SOCKET_ERROR; } } // Select the UDP socket and see if we can write to it if(UDPIsTxPutReady(socket->SocketID, len)) { // Set the proper remote port udpSkt->remotePort = wRemotePort; // Write data and send UDP datagram size = UDPPutArray(socket->SocketID, (uint8_t*)buf, len); UDPFlush(socket->SocketID); return size; } } else if(socket->SocketType == SOCK_STREAM) //TCP will only send to the already established socket. { if(socket->bsdState != SKT_EST) { errno = ENOTCONN; return SOCKET_ERROR; } if(HandlePossibleTCPDisconnection(s)) { errno = ECONNRESET; return SOCKET_ERROR; } // Handle special case were 0 return value is okay if(len == 0) return 0; // Write data to the socket. If one or more bytes were written, then // return this value. Otherwise, fail and return SOCKET_ERROR. size = TCPPutArray(socket->SocketID, (uint8_t*)buf, len); if(size) return size; } errno = EWOULDBLOCK; return SOCKET_ERROR; }
/****************************************************************************** Function: void UDPTask(void) Summary: Performs periodic UDP tasks. Description: This function performs any required periodic UDP tasks. Each socket's state machine is checked, and any elapsed timeout periods are handled. Precondition: UDP is initialized. Parameters: None Returns: None ******************************************************************************/ void UDPTask(void) { UDP_SOCKET ss; for ( ss = 0; ss < MAX_UDP_SOCKETS; ss++ ) { // need to put Extra check if UDP has opened or NOT if((UDPSocketInfo[ss].smState == UDP_OPENED) || (UDPSocketInfo[ss].smState == UDP_CLOSED)) continue; // A timeout has occured. Respond to this timeout condition // depending on what state this socket is in. switch(UDPSocketInfo[ss].smState) { #if defined(STACK_CLIENT_MODE) #if defined(STACK_USE_DNS) case UDP_DNS_RESOLVE: if(DNSBeginUsage()) { // call DNS Resolve function and move to UDP next State machine UDPSocketInfo[ss].smState = UDP_DNS_IS_RESOLVED; if(UDPSocketInfo[ss].flags.bRemoteHostIsROM) DNSResolveROM((ROM BYTE*)(ROM_PTR_BASE)UDPSocketInfo[ss].remote.remoteHost, DNS_TYPE_A); else DNSResolve((BYTE*)(PTR_BASE)UDPSocketInfo[ss].remote.remoteHost, DNS_TYPE_A); } break; case UDP_DNS_IS_RESOLVED: { IP_ADDR ipResolvedDNSIP; // See if DNS resolution has finished. Note that if the DNS // fails, the &ipResolvedDNSIP will be written with 0x00000000. // MyTCB.remote.dwRemoteHost is unioned with // MyTCB.remote.niRemoteMACIP.IPAddr, so we can't directly write // the DNS result into MyTCB.remote.niRemoteMACIP.IPAddr. We // must copy it over only if the DNS is resolution step was // successful. if(DNSIsResolved(&ipResolvedDNSIP)) { if(DNSEndUsage()) { UDPSocketInfo[ss].remote.remoteNode.IPAddr.Val = ipResolvedDNSIP.Val; UDPSocketInfo[ss].smState = UDP_GATEWAY_SEND_ARP; UDPSocketInfo[ss].retryCount = 0; UDPSocketInfo[ss].retryInterval = (TICK_SECOND/4)/256; } else { UDPSocketInfo[ss].smState = UDP_DNS_RESOLVE; } } } break; #endif // #if defined(STACK_USE_DNS) case UDP_GATEWAY_SEND_ARP: // Obtain the MAC address associated with the server's IP address //(either direct MAC address on same subnet, or the MAC address of the Gateway machine) UDPSocketInfo[ss].eventTime = (WORD)TickGetDiv256(); ARPResolve(&UDPSocketInfo[ss].remote.remoteNode.IPAddr); UDPSocketInfo[ss].smState = UDP_GATEWAY_GET_ARP; break; case UDP_GATEWAY_GET_ARP: if(!ARPIsResolved(&UDPSocketInfo[ss].remote.remoteNode.IPAddr, &UDPSocketInfo[ss].remote.remoteNode.MACAddr)) { // Time out if too much time is spent in this state // Note that this will continuously send out ARP // requests for an infinite time if the Gateway // never responds if((WORD)TickGetDiv256() - UDPSocketInfo[ss].eventTime> (WORD)UDPSocketInfo[ss].retryInterval) { // Exponentially increase timeout until we reach 6 attempts then stay constant if(UDPSocketInfo[ss].retryCount < 6u) { UDPSocketInfo[ss].retryCount++; UDPSocketInfo[ss].retryInterval <<= 1; } // Retransmit ARP request UDPSocketInfo[ss].smState = UDP_GATEWAY_SEND_ARP; } } else { UDPSocketInfo[ss].smState = UDP_OPENED; } break; default: case UDP_OPENED: case UDP_CLOSED: // not used break; #endif // #if defined(STACK_CLIENT_MODE) } } }
/********************************************************************* * Function: void GenericTCPClient(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void GenericTCPClient(void) { BYTE i; BYTE *StringPtr; static TICK Timer; static TCP_SOCKET MySocket = INVALID_SOCKET; static NODE_INFO Server; static enum _GenericTCPExampleState { SM_HOME = 0, SM_NAME_RESOLVE, SM_ARP_START_RESOLVE, SM_ARP_RESOLVE, SM_SOCKET_OBTAIN, SM_SOCKET_OBTAINED, SM_PROCESS_RESPONSE, SM_DISCONNECT, SM_DONE } GenericTCPExampleState = SM_DONE; switch(GenericTCPExampleState) { case SM_HOME: // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) break; // Obtain the IP address associated with the common ServerName DNSResolve(ServerName, DNS_TYPE_A); GenericTCPExampleState++; break; case SM_NAME_RESOLVE: // Wait for the DNS server to return the requested IP address if(!DNSIsResolved(&Server.IPAddr)) break; // Release the DNS module, we no longer need it if(!DNSEndUsage()) { // An invalid IP address was returned from the DNS // server. Quit and fail permanantly if host is not valid. GenericTCPExampleState = SM_DONE; break; } GenericTCPExampleState++; case SM_ARP_START_RESOLVE: // Obtain the MAC address associated with the server's IP address (either direct MAC address on same subnet, or the MAC address of the Gateway machine) ARPResolve(&Server.IPAddr); Timer = TickGet(); GenericTCPExampleState++; break; case SM_ARP_RESOLVE: // Wait for the MAC address to finish being obtained if(!ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) { // Time out if too much time is spent in this state if(TickGet()-Timer > 1*TICK_SECOND) { // Retransmit ARP request GenericTCPExampleState--; } break; } GenericTCPExampleState++; case SM_SOCKET_OBTAIN: // Connect a socket to the remote TCP server MySocket = TCPConnect(&Server, ServerPort); // Abort operation if no TCP sockets are available // If this ever happens, incrementing MAX_TCP_SOCKETS in // StackTsk.h may help (at the expense of more global memory // resources). if(MySocket == INVALID_SOCKET) break; GenericTCPExampleState++; Timer = TickGet(); break; case SM_SOCKET_OBTAINED: // Wait for the remote server to accept our connection request if(!TCPIsConnected(MySocket)) { // Time out if too much time is spent in this state if(TickGet()-Timer > 5*TICK_SECOND) { // Close the socket so it can be used by other modules TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; GenericTCPExampleState--; } break; } Timer = TickGet(); // Make certain the socket can be written to if(!TCPIsPutReady(MySocket)) break; // Place the application protocol data into the transmit buffer. For this example, we are connected to an HTTP server, so we'll send an HTTP GET request. TCPPutROMString(MySocket, (ROM BYTE*)"GET "); TCPPutROMString(MySocket, RemoteURL); TCPPutROMString(MySocket, (ROM BYTE*)" HTTP/1.1\r\nHost: "); TCPPutString(MySocket, ServerName); TCPPutROMString(MySocket, (ROM BYTE*)"\r\n\r\n"); // Send the packet TCPFlush(MySocket); GenericTCPExampleState++; case SM_PROCESS_RESPONSE: // Check to see if the remote node has disconnected from us or sent us any application data // If application data is available, write it to the UART if(!TCPIsConnected(MySocket)) { GenericTCPExampleState++; } if(!TCPIsGetReady(MySocket)) break; // Obtain the server reply while(TCPGet(MySocket, &i)) { while(BusyUART()); WriteUART(i); } break; case SM_DISCONNECT: // Close the socket so it can be used by other modules // For this application, we wish to stay connected, but this state will still get entered if the remote server decides to disconnect TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; GenericTCPExampleState = SM_DONE; break; case SM_DONE: // Do nothing unless the user pushes BUTTON1 and wants to restart the whole connection/download process if(BUTTON1_IO == 0u) GenericTCPExampleState = SM_HOME; break; } }
/********************************************************************* * Function: LONG ICMPGetReply(void) * * PreCondition: ICMPBeginUsage() returned TRUE and ICMPSendPing() * was called * * Input: None * * Output: -3: Could not resolve hostname (DNS timeout or * hostname invalid) * -2: No response received yet * -1: Operation timed out (longer than ICMP_TIMEOUT) * has elapsed. * >=0: Number of TICKs that elapsed between * initial ICMP transmission and reception of * a valid echo. * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ LONG ICMPGetReply(void) { ICMP_PACKET ICMPPacket; switch(ICMPState) { #if defined(STACK_USE_DNS) case SM_DNS_SEND_QUERY: // Obtain DNS module ownership if(!DNSBeginUsage()) break; // Send DNS query if(ICMPFlags.bRemoteHostIsROM) DNSResolveROM(StaticVars.RemoteHost.szROM, DNS_TYPE_A); else DNSResolve(StaticVars.RemoteHost.szRAM, DNS_TYPE_A); ICMPState = SM_DNS_GET_RESPONSE; break; case SM_DNS_GET_RESPONSE: // See if DNS is done, and if so, get the remote IP address if(!DNSIsResolved(&StaticVars.ICMPRemote.IPAddr)) break; // Free the DNS module DNSEndUsage(); // Return error code if the DNS query failed if(StaticVars.ICMPRemote.IPAddr.Val == 0x00000000ul) { ICMPState = SM_IDLE; return -3; } ICMPState = SM_ARP_SEND_QUERY; // No break; #endif case SM_ARP_SEND_QUERY: ARPResolve(&StaticVars.ICMPRemote.IPAddr); ICMPState = SM_ARP_GET_RESPONSE; break; case SM_ARP_GET_RESPONSE: // See if the ARP reponse was successfully received if(!ARPIsResolved(&StaticVars.ICMPRemote.IPAddr, &StaticVars.ICMPRemote.MACAddr)) break; ICMPState = SM_ICMP_SEND_ECHO_REQUEST; // No break; case SM_ICMP_SEND_ECHO_REQUEST: if(!IPIsTxReady()) break; // Set up the ping packet ICMPPacket.vType = 0x08; // 0x08: Echo (ping) request ICMPPacket.vCode = 0x00; ICMPPacket.wChecksum = 0x0000; ICMPPacket.wIdentifier = 0xEFBE; wICMPSequenceNumber++; ICMPPacket.wSequenceNumber = wICMPSequenceNumber; ICMPPacket.wData = 0x2860; ICMPPacket.wChecksum = CalcIPChecksum((BYTE*)&ICMPPacket, sizeof(ICMPPacket)); // Record the current time. This will be used as a basis for // finding the echo response time, which exludes the ARP and DNS // steps ICMPTimer = TickGet(); // Position the write pointer for the next IPPutHeader operation MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER)); // Create IP header in TX memory IPPutHeader(&StaticVars.ICMPRemote, IP_PROT_ICMP, sizeof(ICMPPacket)); MACPutArray((BYTE*)&ICMPPacket, sizeof(ICMPPacket)); MACFlush(); // Echo sent, advance state ICMPState = SM_ICMP_GET_ECHO_RESPONSE; break; case SM_ICMP_GET_ECHO_RESPONSE: // See if the echo was successfully received if(ICMPFlags.bReplyValid) return (LONG)ICMPTimer; break; // SM_IDLE or illegal/impossible state: default: return -1; } // See if the DNS/ARP/echo request timed out if(TickGet() - ICMPTimer > ICMP_TIMEOUT) { // Free DNS module if we have it in use #if defined(STACK_USE_DNS) if(ICMPState == SM_DNS_GET_RESPONSE) DNSEndUsage(); #endif // Stop ICMP echo test and return error to caller ICMPState = SM_IDLE; return -1; } // Still working. No response to report yet. return -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; }
/***************************************************************************** Function: void SNTPClient(void) Summary: Periodically checks the current time from a pool of servers. Description: This function periodically checks a pool of time servers to obtain the current date/time. Precondition: UDP is initialized. Parameters: None Returns: None Remarks: This function requires once available UDP socket while processing, but frees that socket when the SNTP module is idle. ***************************************************************************/ void SNTPClient(void) { NTP_PACKET pkt; WORD w; // static NODE_INFO Server; static DWORD dwTimer; static UDP_SOCKET MySocket = INVALID_UDP_SOCKET; static enum { SM_HOME = 0, SM_UDP_IS_OPENED, //SM_NAME_RESOLVE, //SM_ARP_START_RESOLVE, //SM_ARP_RESOLVE, //SM_ARP_START_RESOLVE2, //SM_ARP_RESOLVE2, //SM_ARP_START_RESOLVE3, //SM_ARP_RESOLVE3, //SM_ARP_RESOLVE_FAIL, SM_UDP_SEND, SM_UDP_RECV, SM_SHORT_WAIT, SM_WAIT } SNTPState = SM_HOME; switch(SNTPState) { case SM_HOME: if(MySocket == INVALID_UDP_SOCKET) MySocket = UDPOpenEx((DWORD)(PTR_BASE)NTP_SERVER,UDP_OPEN_ROM_HOST,0,NTP_SERVER_PORT); SNTPState++; break; case SM_UDP_IS_OPENED: if(UDPIsOpened(MySocket) == TRUE) { SNTPState = SM_UDP_SEND; } /* else { UDPClose(MySocket); SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; } */ break; #if 0 // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) break; // Obtain the IP address associated with the server name DNSResolveROM((ROM BYTE*)NTP_SERVER, DNS_TYPE_A); dwTimer = TickGet(); SNTPState = SM_NAME_RESOLVE; break; case SM_NAME_RESOLVE: // Wait for DNS resolution to complete if(!DNSIsResolved(&Server.IPAddr)) { if((TickGet() - dwTimer) > (5 * TICK_SECOND)) { DNSEndUsage(); dwTimer = TickGetDiv64K(); SNTPState = SM_SHORT_WAIT; } break; } // Obtain DNS resolution result if(!DNSEndUsage()) { // No valid IP address was returned from the DNS // server. Quit and fail for a while if host is not valid. dwTimer = TickGetDiv64K(); SNTPState = SM_SHORT_WAIT; break; } SNTPState = SM_ARP_START_RESOLVE; // No need to break case SM_ARP_START_RESOLVE: case SM_ARP_START_RESOLVE2: case SM_ARP_START_RESOLVE3: // Obtain the MAC address associated with the server's IP address ARPResolve(&Server.IPAddr); dwTimer = TickGet(); SNTPState++; break; case SM_ARP_RESOLVE: case SM_ARP_RESOLVE2: case SM_ARP_RESOLVE3: // Wait for the MAC address to finish being obtained if(!ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) { // Time out if too much time is spent in this state if(TickGet() - dwTimer > 1*TICK_SECOND) { // Retransmit ARP request by going to next SM_ARP_START_RESOLVE state or fail by going to SM_ARP_RESOLVE_FAIL state. SNTPState++; } break; } SNTPState = SM_UDP_SEND; break; case SM_ARP_RESOLVE_FAIL: // ARP failed after 3 tries, abort and wait for next time query dwTimer = TickGetDiv64K(); SNTPState = SM_SHORT_WAIT; break; #endif // case SM_UDP_IS_OPENED: case SM_UDP_SEND: // Open up the sending UDP socket //MySocket = UDPOpen(0, &Server, NTP_SERVER_PORT); #if 0 MySocket = UDPOpenEx(NTP_SERVER,UDP_OPEN_ROM_HOST,0,NTP_SERVER_PORT); if(MySocket == INVALID_UDP_SOCKET) break; #endif // Make certain the socket can be written to if(!UDPIsPutReady(MySocket)) { UDPClose(MySocket); SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; break; } // Transmit a time request packet memset(&pkt, 0, sizeof(pkt)); pkt.flags.versionNumber = 3; // NTP Version 3 pkt.flags.mode = 3; // NTP Client pkt.orig_ts_secs = swapl(NTP_EPOCH); UDPPutArray((BYTE*) &pkt, sizeof(pkt)); UDPFlush(); dwTimer = TickGet(); SNTPState = SM_UDP_RECV; break; case SM_UDP_RECV: // Look for a response time packet if(!UDPIsGetReady(MySocket)) { if((TickGet()) - dwTimer > NTP_REPLY_TIMEOUT) { // Abort the request and wait until the next timeout period UDPClose(MySocket); //dwTimer = TickGetDiv64K(); //SNTPState = SM_SHORT_WAIT; SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; break; } break; } // Get the response time packet w = UDPGetArray((BYTE*) &pkt, sizeof(pkt)); UDPClose(MySocket); dwTimer = TickGetDiv64K(); SNTPState = SM_WAIT; MySocket = INVALID_UDP_SOCKET; // Validate packet size if(w != sizeof(pkt)) { break; } // Set out local time to match the returned time dwLastUpdateTick = TickGet(); dwSNTPSeconds = swapl(pkt.tx_ts_secs) - NTP_EPOCH; // Do rounding. If the partial seconds is > 0.5 then add 1 to the seconds count. if(((BYTE*)&pkt.tx_ts_fraq)[0] & 0x80) dwSNTPSeconds++; #ifdef WIFI_NET_TEST wifi_net_test_print("SNTP: current time", dwSNTPSeconds); #endif break; case SM_SHORT_WAIT: // Attempt to requery the NTP server after a specified NTP_FAST_QUERY_INTERVAL time (ex: 8 seconds) has elapsed. if(TickGetDiv64K() - dwTimer > (NTP_FAST_QUERY_INTERVAL/65536ull)) { SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; } break; case SM_WAIT: // Requery the NTP server after a specified NTP_QUERY_INTERVAL time (ex: 10 minutes) has elapsed. if(TickGetDiv64K() - dwTimer > (NTP_QUERY_INTERVAL/65536ull)) { SNTPState = SM_HOME; MySocket = INVALID_UDP_SOCKET; } break; } }
void timeSync(void) { BYTE i; signed char j; static TICK Timer; static TICK perodicTick = 0; static TICK t = 0; static TCP_SOCKET MySocket = INVALID_SOCKET; static NODE_INFO Server; static int arp_tries = 0; static int tcp_tries = 0; BYTE rcnt=0; BYTE ncnt=0; char foundData=0; if ((tickGet()-t) >= TICK_1S ) { t = tickGet(); timeNow++; } switch(smTS) { case SM_START: #if defined(TIMESYNC_DEBUG) putrsUART("Start!\r\n"); #endif // Set IP adress to connect to. Server.IPAddr.v[0]=193; Server.IPAddr.v[1]=11; Server.IPAddr.v[2]=249; Server.IPAddr.v[3]=54; arp_tries = 0; tcp_tries = 0; smTS = SM_ARP_RESOLVE; break; case SM_ARP_RESOLVE: #if defined(TIMESYNC_DEBUG) putrsUART("Resolve..\r\n"); #endif // If ARP is redy.. if (ARPIsTxReady()) { // Resolve the IP adress.. ARPResolve(&Server.IPAddr); arp_tries++; Timer = tickGet(); smTS = SM_ARP_RESOLVED; } break; case SM_ARP_RESOLVED: #if defined(TIMESYNC_DEBUG) putrsUART("Resolved..\r\n"); #endif // If IP adress is resolved, go to next state if (ARPIsResolved(&Server.IPAddr, &Server.MACAddr)) { smTS = SM_CONNECT; } // If not resolved and spent long time here, // Go back to previous state and re-resolve. else if (tickGet()-Timer > 1*TICK_1S) { smTS = SM_ARP_RESOLVE; } else if (arp_tries>=MAX_ARP_TRIES) { //Abort smTS = SM_ABORT; } break; case SM_CONNECT: #if defined(TIMESYNC_DEBUG) putrsUART("Connect..\r\n"); #endif // We have an sucessfull ARP, connect.. MySocket = TCPConnect(&Server, ServerPort); tcp_tries++; if(MySocket == INVALID_SOCKET) { // Do something. } Timer = tickGet(); smTS = SM_CONNECT_WAIT; break; case SM_CONNECT_WAIT: #if defined(TIMESYNC_DEBUG) putrsUART("Connect wait..\r\n"); #endif // Wait for connection.. if (TCPIsConnected(MySocket)) { smTS = SM_CONNECTED; } // If not connected and spent long time here, // Go back to previous state and re-connect. else if (tickGet()-Timer > 5*TICK_1S) { TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; smTS = SM_CONNECT; } else if (tcp_tries>=MAX_TCP_TRIES) { //Abort TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; smTS = SM_ABORT; } break; case SM_CONNECTED: #if defined(TIMESYNC_DEBUG) putrsUART("Connected..\r\n"); #endif // Send data. Timer = tickGet(); if(TCPIsPutReady(MySocket)) { TCPPut(MySocket, 'G'); TCPPut(MySocket, 'E'); TCPPut(MySocket, 'T'); TCPPut(MySocket, ' '); TCPPut(MySocket, '/'); TCPPut(MySocket, 't'); TCPPut(MySocket, 'i'); TCPPut(MySocket, 'm'); TCPPut(MySocket, 'e'); TCPPut(MySocket, '.'); TCPPut(MySocket, 'p'); TCPPut(MySocket, 'h'); TCPPut(MySocket, 'p'); TCPPut(MySocket, ' '); TCPPut(MySocket, 'H'); TCPPut(MySocket, 'T'); TCPPut(MySocket, 'T'); TCPPut(MySocket, 'P'); TCPPut(MySocket, '/'); TCPPut(MySocket, '1'); TCPPut(MySocket, '.'); TCPPut(MySocket, '0'); TCPPut(MySocket, '\r'); TCPPut(MySocket, '\n'); TCPPut(MySocket, '\r'); TCPPut(MySocket, '\n'); // Send the packet TCPFlush(MySocket); smTS = SM_RECEIVE; } break; case SM_RECEIVE: #if defined(TIMESYNC_DEBUG) putrsUART("Receive..\r\n"); #endif // Client disconnected. if(!TCPIsConnected(MySocket)) { smTS = SM_ABORT; break; } if(TCPIsGetReady(MySocket)) { while(TCPGet(MySocket, &i)) { if (i==CR) rcnt++; else if(i==LF) ncnt++; else { rcnt=0; ncnt=0; } if (foundData==1) { if (j>=0) { timeNow=timeNow+(((DWORD)i)<<(8*j--)); #if defined(TIMESYNC_DEBUG) while(BusyUART()); WriteUART(i); #endif } } if(rcnt>1 && ncnt>1) {j=3; timeNow=0; foundData=1;} } smTS = SM_DISCONNECT; } break; case SM_DISCONNECT: #if defined(TIMESYNC_DEBUG) putrsUART("\r\nDisconnect\r\n"); #endif foundData=0; t = tickGet(); lastSync = timeNow; perodicTick=tickGet(); TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; smTS = SM_DONE; break; case SM_ABORT: #if defined(TIMESYNC_DEBUG) putrsUART("Abort...\r\n"); #endif smTS = SM_START; break; case SM_DONE: if (tickGet()-perodicTick > SYNC_INTERVAL*TICK_1S) { #if defined(TIMESYNC_DEBUG) putrsUART("GO!\r\n"); #endif smTS = SM_START; } break; default: smTS = SM_START; break; } }