static void TCPIP_SMTP_ClientProcess(void) { uint8_t i; uint16_t w; uint8_t vBase64Buffer[4]; static uint32_t SMTPTimer; static uint8_t RXBuffer[4]; static const uint8_t *ROMStrPtr, *ROMStrPtr2; static const uint8_t *RAMStrPtr; static uint16_t wAddressLength; TCPIP_DNS_RESULT dnsRes; DNS_RESOLVE_TYPE dnsType; switch(TransportState) { case TRANSPORT_HOME: // TCPIP_SMTP_UsageBegin() is the only function which will kick // the state machine into the next state break; case TRANSPORT_BEGIN: // Wait for the user to program all the pointers and then // call TCPIP_SMTP_MailSend() if(!SMTPFlags.bits.ReadyToStart) { break; } SMTPClient.Server = FindEmailServer(&SMTPClient, &dnsType); // See if we found a hostname anywhere which we could resolve if(!(SMTPClient.Server)) { ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; break; } // check for a plain IP address if(TCPIP_Helper_StringToIPAddress(SMTPClient.Server, &SMTPServer)) { TransportState = TRANSPORT_OBTAIN_SOCKET; break; } // use DNS to resolve the name TCPIP_DNS_Resolve(SMTPClient.Server, dnsType); SMTPTimer = SYS_TMR_TickCountGet(); TransportState++; break; case TRANSPORT_NAME_RESOLVE: // Wait for the DNS server to return the requested IP address dnsRes = TCPIP_DNS_IsResolved((const char*)SMTPClient.Server,&SMTPServer); if(dnsRes == DNS_RES_PENDING) { break; } if(dnsRes < 0) { // some error occurred ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; break; } // DNS_RES_OK TransportState++; // No need to break here case TRANSPORT_OBTAIN_SOCKET: // Connect a TCP socket to the remote SMTP server MySocket = TCPIP_TCP_ClientOpen(IP_ADDRESS_TYPE_IPV4, SMTPClient.ServerPort, (IP_MULTI_ADDRESS*)&SMTPServer.Val); // Abort operation if no TCP socket could be opened. // If this ever happens, you need to update your tcp_config.h if(MySocket == INVALID_SOCKET) break; TCPIP_TCP_SignalHandlerRegister(MySocket, TCPIP_TCP_SIGNAL_RX_DATA, _SMTPSocketRxSignalHandler, 0); TransportState++; SMTPTimer = SYS_TMR_TickCountGet(); // No break; fall into TRANSPORT_SOCKET_OBTAINED case TRANSPORT_SOCKET_OBTAINED: if(!TCPIP_TCP_IsConnected(MySocket)) { // Don't stick around in the wrong state if the // server was connected, but then disconnected us. // Also time out if we can't establish the connection // to the SMTP server if(SMTPFlags.bits.ConnectedOnce || ((SYS_TMR_TickCountGet()-SMTPTimer) > (TCPIP_SMTP_SERVER_REPLY_TIMEOUT * SYS_TMR_TickCounterFrequencyGet()))) { ResponseCode = SMTP_CONNECT_ERROR; TransportState = TRANSPORT_CLOSE; } break; } SMTPFlags.bits.ConnectedOnce = true; // See if the server sent us anything while(TCPIP_TCP_GetIsReady(MySocket)) { TCPIP_TCP_Get(MySocket, &i); switch(RXParserState) { case RX_BYTE_0: case RX_BYTE_1: case RX_BYTE_2: RXBuffer[RXParserState] = i; RXParserState++; break; case RX_BYTE_3: switch(i) { case ' ': SMTPFlags.bits.RXSkipResponse = false; RXParserState++; break; case '-': SMTPFlags.bits.RXSkipResponse = true; RXParserState++; break; case '\r': RXParserState = RX_SEEK_LF; break; } break; case RX_SEEK_CR: if(i == '\r') RXParserState++; break; case RX_SEEK_LF: // If we received the whole command if(i == '\n') { RXParserState = RX_BYTE_0; if(!SMTPFlags.bits.RXSkipResponse) { // The server sent us a response code // Null terminate the ASCII reponse code so we can convert it to an integer RXBuffer[3] = 0; ResponseCode = atoi((char*)RXBuffer); // Handle the response switch(SMTPState) { case SMTP_HELO_ACK: if(ResponseCode >= 200u && ResponseCode <= 299u) { if(SMTPClient.Username) SMTPState = SMTP_AUTH_LOGIN; else SMTPState = SMTP_MAILFROM; } else SMTPState = SMTP_QUIT_INIT; break; case SMTP_AUTH_LOGIN_ACK: case SMTP_AUTH_USERNAME_ACK: if(ResponseCode == 334u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_AUTH_PASSWORD_ACK: if(ResponseCode == 235u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_HOME: case SMTP_MAILFROM_ACK: case SMTP_RCPTTO_ACK: case SMTP_RCPTTOCC_ACK: case SMTP_RCPTTOBCC_ACK: if(ResponseCode >= 200u && ResponseCode <= 299u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_DATA_ACK: if(ResponseCode == 354u) SMTPState++; else SMTPState = SMTP_QUIT_INIT; break; case SMTP_DATA_BODY_ACK: if(ResponseCode >= 200u && ResponseCode <= 299u) SMTPFlags.bits.SentSuccessfully = true; SMTPState = SMTP_QUIT_INIT; break; // Default case needed to supress compiler diagnostics default: break; } } } else if(i != '\r') RXParserState--; break; } } // Generate new data in the TX buffer, as needed, if possible if(TCPIP_TCP_PutIsReady(MySocket) < 64u) break; switch(SMTPState) { case SMTP_HELO: if(SMTPClient.Username == NULL) TCPIP_TCP_StringPut(MySocket, (uint8_t*)"HELO MCHPBOARD\r\n"); else TCPIP_TCP_StringPut(MySocket, (uint8_t*)"EHLO MCHPBOARD\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_AUTH_LOGIN: // Note: This state is only entered from SMTP_HELO_ACK if the application // has specified a Username to use (SMTPClient.Username is non-NULL) TCPIP_TCP_StringPut(MySocket, (uint8_t*)"AUTH LOGIN\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_AUTH_USERNAME: // Base 64 encode and transmit the username. RAMStrPtr = (uint8_t*)SMTPClient.Username; w = strlen((char*)RAMStrPtr); while(w) { i = 0; while((i < w) && (i < sizeof(vBase64Buffer)*3/4)) { vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; TCPIP_Helper_Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer)); TCPIP_TCP_ArrayPut(MySocket, vBase64Buffer, sizeof(vBase64Buffer)); } TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_AUTH_PASSWORD: // Base 64 encode and transmit the password RAMStrPtr = (uint8_t*)SMTPClient.Password; w = strlen((char*)RAMStrPtr); while(w) { i = 0; while((i < w) && (i < sizeof(vBase64Buffer)*3/4)) { vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; TCPIP_Helper_Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer)); TCPIP_TCP_ArrayPut(MySocket, vBase64Buffer, sizeof(vBase64Buffer)); } TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_MAILFROM: // Send MAIL FROM header. Note that this is for the SMTP server validation, // not what actually will be displayed in the recipients mail client as a // return address. TCPIP_TCP_StringPut(MySocket, (uint8_t*)"MAIL FROM:<"); RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.From, &wAddressLength); TCPIP_TCP_ArrayPut(MySocket, RAMStrPtr, wAddressLength); TCPIP_TCP_StringPut(MySocket, (uint8_t*)">\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_RCPTTO_INIT: // See if there are any (To) recipients to process if(SMTPClient.To) { RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.To, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTO; break; } } SMTPState = SMTP_RCPTTOCC_INIT; break; case SMTP_RCPTTO: case SMTP_RCPTTOCC: case SMTP_RCPTTOBCC: TCPIP_TCP_StringPut(MySocket, (uint8_t*)"RCPT TO:<"); TCPIP_TCP_ArrayPut(MySocket, RAMStrPtr, wAddressLength); TCPIP_TCP_StringPut(MySocket, (uint8_t*)">\r\n"); TCPIP_TCP_Flush(MySocket); SMTPState++; break; case SMTP_RCPTTO_ISDONE: // See if we have any more (To) recipients to process // If we do, we must roll back a couple of states RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTO; break; } // All done with To field SMTPState++; //No break case SMTP_RCPTTOCC_INIT: // See if there are any Carbon Copy (CC) recipients to process if(SMTPClient.CC) { RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.CC, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOCC; break; } } SMTPState = SMTP_RCPTTOBCC_INIT; break; case SMTP_RCPTTOCC_ISDONE: // See if we have any more Carbon Copy (CC) recipients to process // If we do, we must roll back a couple of states RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOCC; break; } // All done with CC field SMTPState++; //No break case SMTP_RCPTTOBCC_INIT: // See if there are any Blind Carbon Copy (BCC) recipients to process if(SMTPClient.BCC) { RAMStrPtr = FindEmailAddress((uint8_t*)SMTPClient.BCC, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOBCC; break; } } // All done with BCC field SMTPState = SMTP_DATA; break; case SMTP_RCPTTOBCC_ISDONE: // See if we have any more Blind Carbon Copy (CC) recipients to process // If we do, we must roll back a couple of states RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOBCC; break; } // All done with BCC field SMTPState++; //No break case SMTP_DATA: TCPIP_TCP_StringPut(MySocket, (uint8_t*)"DATA\r\n"); SMTPState++; PutHeadersState = PUTHEADERS_FROM_INIT; TCPIP_TCP_Flush(MySocket); break; case SMTP_DATA_HEADER: while((PutHeadersState != PUTHEADERS_DONE) && (TCPIP_TCP_PutIsReady(MySocket) > 64u)) { switch(PutHeadersState) { case PUTHEADERS_FROM_INIT: if(SMTPClient.From) { PutHeadersState = PUTHEADERS_FROM; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"From: "); } else { PutHeadersState = PUTHEADERS_TO_INIT; } break; case PUTHEADERS_FROM: SMTPClient.From = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.From); if(*SMTPClient.From == 0u) PutHeadersState = PUTHEADERS_TO_INIT; break; case PUTHEADERS_TO_INIT: if(SMTPClient.To) { PutHeadersState = PUTHEADERS_TO; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\nTo: "); } else { PutHeadersState = PUTHEADERS_CC_INIT; } break; case PUTHEADERS_TO: SMTPClient.To = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.To); if(*SMTPClient.To == 0u) PutHeadersState = PUTHEADERS_CC_INIT; break; case PUTHEADERS_CC_INIT: if(SMTPClient.CC) { PutHeadersState = PUTHEADERS_CC; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\nCC: "); } else { PutHeadersState = PUTHEADERS_SUBJECT_INIT; } break; case PUTHEADERS_CC: SMTPClient.CC = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.CC); if(*SMTPClient.CC == 0u) PutHeadersState = PUTHEADERS_SUBJECT_INIT; break; case PUTHEADERS_SUBJECT_INIT: if(SMTPClient.Subject) { PutHeadersState = PUTHEADERS_SUBJECT; TCPIP_TCP_StringPut(MySocket, (uint8_t*)"\r\nSubject: "); } else { PutHeadersState = PUTHEADERS_OTHER_INIT; } break; case PUTHEADERS_SUBJECT: SMTPClient.Subject = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.Subject); if(*SMTPClient.Subject == 0u) PutHeadersState = PUTHEADERS_OTHER_INIT; break; case PUTHEADERS_OTHER_INIT: TCPIP_TCP_ArrayPut(MySocket, (uint8_t*)"\r\n", 2); if(SMTPClient.OtherHeaders) { PutHeadersState = PUTHEADERS_OTHER; } else { TCPIP_TCP_ArrayPut(MySocket, (uint8_t*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } break; case PUTHEADERS_OTHER: SMTPClient.OtherHeaders = (char*)TCPIP_TCP_StringPut(MySocket, (uint8_t*)SMTPClient.OtherHeaders); if(*SMTPClient.OtherHeaders == 0u) { TCPIP_TCP_ArrayPut(MySocket, (uint8_t*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } break; // Default case needed to supress compiler diagnostics default: break; } } TCPIP_TCP_Flush(MySocket); break; case SMTP_DATA_BODY_INIT: SMTPState++; RAMStrPtr = (uint8_t*)SMTPClient.Body; ROMStrPtr2 = (const uint8_t*)"\r\n.\r\n"; CRPeriod.Pos = NULL; if(RAMStrPtr) CRPeriod.Pos = (uint8_t*)strstr((char*)RAMStrPtr, (const char*)"\r\n."); // No break here case SMTP_DATA_BODY: if(SMTPClient.Body) { if(*ROMStrPtr2) { // Put the application data, doing the transparancy replacement of "\r\n." with "\r\n.." while(CRPeriod.Pos) { CRPeriod.Pos += 3; RAMStrPtr += TCPIP_TCP_ArrayPut(MySocket, RAMStrPtr, CRPeriod.Pos-RAMStrPtr); if(RAMStrPtr == CRPeriod.Pos) { if(!TCPIP_TCP_Put(MySocket, '.')) { CRPeriod.Pos -= 3; break; } } else { CRPeriod.Pos -= 3; break; } CRPeriod.Pos = (uint8_t*)strstr((char*)RAMStrPtr, (const char*)"\r\n."); } // If we get down here, either all replacements have been made or there is no remaining space in the TCP output buffer RAMStrPtr = TCPIP_TCP_StringPut(MySocket, RAMStrPtr); ROMStrPtr2 = TCPIP_TCP_StringPut(MySocket, (uint8_t*)ROMStrPtr2); TCPIP_TCP_Flush(MySocket); } } else { if(SMTPFlags.bits.ReadyToFinish) { if(*ROMStrPtr2) { ROMStrPtr2 = TCPIP_TCP_StringPut(MySocket, (uint8_t*)ROMStrPtr2); TCPIP_TCP_Flush(MySocket); } } } if(*ROMStrPtr2 == 0u) { SMTPState++; } break; case SMTP_QUIT_INIT: SMTPState++; ROMStrPtr = (const uint8_t*)"QUIT\r\n"; // No break here case SMTP_QUIT: if(*ROMStrPtr) { ROMStrPtr = TCPIP_TCP_StringPut(MySocket, (uint8_t*)ROMStrPtr); TCPIP_TCP_Flush(MySocket); } if(*ROMStrPtr == 0u) { TransportState = TRANSPORT_CLOSE; } break; // Default case needed to supress compiler diagnostics default: break; } break; case TRANSPORT_CLOSE: // Close the socket so it can be used by other modules TCPIP_TCP_Close(MySocket); MySocket = INVALID_SOCKET; // Go back to doing nothing TransportState = TRANSPORT_HOME; break; } }
// ddns_manager.h void TCPIP_DDNS_Task(void) { uint8_t i; uint16_t wPos; DNS_RESULT dnsRes; static enum { SM_IDLE = 0u, SM_BEGIN_CHECKIP, SM_DNS_START_RESOLVE, SM_DNS_WAIT_RESOLVE, SM_CHECKIP_SKT_OBTAINED, SM_CHECKIP_FIND_DELIMITER, SM_CHECKIP_FIND_ADDRESS, SM_CHECKIP_DISCONNECT, SM_IP_UPDATE_HOME, SM_IP_UPDATE_WAIT_DNS, SM_IP_UPDATE_SKT_OBTAINED, /* HTTP request msg is divided into 6 parts SM_IP_UPDATE_REQ_A,B,C,D,E,F as the tcp ip tx buffer is only able to carry 200 bytes at a time. */ SM_IP_UPDATE_REQ_A, //0x8 SM_IP_UPDATE_REQ_B, //0x9 SM_IP_UPDATE_REQ_C, //0xa SM_IP_UPDATE_REQ_D, //0xb SM_IP_UPDATE_REQ_E, //0xc SM_IP_UPDATE_REQ_F, //0xd SM_IPUPDATE_FIND_RESPONSE, //0xe SM_IPUPDATE_PARSE_RESPONSE, //0xf SM_IPUDATE_DISCONNECT, //0x10 SM_DONE, // Done, try again in 10 minutes SM_DNS_ERROR, // DNS resolver error, try again in 30 seconds SM_SKT_ERROR, // socket open error, try again in 30 seconds SM_SOFT_ERROR, // Soft error, try again in 30 seconds SM_SYSTEM_ERROR // System error, try again in 30 minutes } smDDNS = SM_IDLE; switch(smDDNS) { case SM_IDLE: // Wait for timeout to begin IP check if(SYS_TICK_Get() > dwUpdateAt) break; // Otherwise, continue to next state smDDNS = SM_BEGIN_CHECKIP; case SM_BEGIN_CHECKIP: // If a fatal error has occurred, abort to the SM_DONE state and keep // the error message. if(lastStatus >= DDNS_STATUS_ABUSE && lastStatus <= DDNS_STATUS_911) { smDDNS = SM_DONE; break; } // If DDNSClient is not properly configured, abort if( // Verify that each pointer is not null, and is not empty (DDNSClient.ROMPointers.Host && (!DDNSClient.Host.szROM || *DDNSClient.Host.szROM == '\0') ) || (!DDNSClient.ROMPointers.Host && (!DDNSClient.Host.szRAM || *DDNSClient.Host.szRAM == '\0') ) || (DDNSClient.ROMPointers.Username && (!DDNSClient.Username.szROM || *DDNSClient.Username.szROM == '\0') ) || (!DDNSClient.ROMPointers.Username && (!DDNSClient.Username.szRAM || *DDNSClient.Username.szRAM == '\0') ) || (DDNSClient.ROMPointers.Password && (!DDNSClient.Password.szROM || *DDNSClient.Password.szROM == '\0') ) || (!DDNSClient.ROMPointers.Password && (!DDNSClient.Password.szRAM || *DDNSClient.Password.szRAM == '\0') ) || (DDNSClient.ROMPointers.CheckIPServer && (!DDNSClient.CheckIPServer.szROM || *DDNSClient.CheckIPServer.szROM == '\0') ) || (!DDNSClient.ROMPointers.CheckIPServer && (!DDNSClient.CheckIPServer.szRAM || *DDNSClient.CheckIPServer.szRAM == '\0') ) || (DDNSClient.ROMPointers.UpdateServer && (!DDNSClient.UpdateServer.szROM || *DDNSClient.UpdateServer.szROM == '\0') ) || (!DDNSClient.ROMPointers.UpdateServer && (!DDNSClient.UpdateServer.szRAM || *DDNSClient.UpdateServer.szRAM == '\0') ) ) { smDDNS = SM_SOFT_ERROR; lastStatus = DDNS_STATUS_INVALID; break; } // Start with an invalidated IP String vBuffer[0] = '\0'; smDDNS++; break; case SM_DNS_START_RESOLVE: netH = TCPIP_STACK_NetDefaultGet(); if(TCPIP_DNS_UsageBegin(netH) != DNS_RES_OK) { lastStatus = DDNS_STATUS_DNS_ERROR; smDDNS = SM_DNS_ERROR; break; } // resolve the remote server if(DDNSClient.ROMPointers.CheckIPServer) { TCPIP_DNS_Resolve((const char*)DDNSClient.CheckIPServer.szROM, DNS_TYPE_A); } else { TCPIP_DNS_Resolve((const char*)DDNSClient.CheckIPServer.szRAM, DNS_TYPE_A); } smDDNS++; break; case SM_DNS_WAIT_RESOLVE: if(DDNSClient.ROMPointers.CheckIPServer) { dnsRes = TCPIP_DNS_IsResolved((const char*)DDNSClient.CheckIPServer.szROM, &ddnsServerIP); } else { dnsRes = TCPIP_DNS_IsResolved((const char*)DDNSClient.CheckIPServer.szRAM, &ddnsServerIP); } if(dnsRes == DNS_RES_PENDING) { // ongoing operation; break; } TCPIP_DNS_UsageEnd(netH); if(dnsRes < 0) { // some DNS error occurred; retry later lastStatus = DDNS_STATUS_DNS_ERROR; smDDNS = SM_DNS_ERROR; break; } // server IP solved // open the client socket MySocket = TCPIP_TCP_ClientOpen(IP_ADDRESS_TYPE_IPV4, DDNSClient.CheckIPPort, (IP_MULTI_ADDRESS*)&ddnsServerIP); // If no socket available, try again later if(MySocket == INVALID_SOCKET) { lastStatus = DDNS_STATUS_SKT_ERROR; smDDNS = SM_SKT_ERROR; break; } // socket opened OK smDDNS++; DDnsTimer = SYS_TICK_Get(); break; case SM_CHECKIP_SKT_OBTAINED: // Wait for the remote server to accept our connection request if(!TCPIP_TCP_IsConnected(MySocket)) { // Time out if too much time is spent in this state if(SYS_TICK_Get()-DDnsTimer > 6*SYS_TICK_TicksPerSecondGet()) { // Close the socket so it can be used by other modules // We will retry soon TCPIP_TCP_Close(MySocket); MySocket = INVALID_SOCKET; lastStatus = DDNS_STATUS_CHECKIP_ERROR; smDDNS = SM_SOFT_ERROR; } break; } DDnsTimer = SYS_TICK_Get(); // Make certain the socket can be written to if(TCPIP_TCP_PutIsReady(MySocket) < 125u)//125 = size of TCP Tx buffer break; // Transmit the request to the server TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"GET / HTTP/1.0\r\nHost: "); if(DDNSClient.ROMPointers.CheckIPServer) { TCPIP_TCP_StringPut(MySocket, DDNSClient.CheckIPServer.szROM); } else { TCPIP_TCP_StringPut(MySocket, DDNSClient.CheckIPServer.szRAM); } TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"\r\nConnection: close\r\n\r\n"); // Send the packet TCPIP_TCP_Flush(MySocket); smDDNS++; break; case SM_CHECKIP_FIND_DELIMITER: // Check if remote node is still connected. If not, force to the disconnect state, // but don't break because data may still be waiting. if(!TCPIP_TCP_IsConnected(MySocket) || SYS_TICK_Get() - DDnsTimer > 6*SYS_TICK_TicksPerSecondGet()) smDDNS = SM_CHECKIP_DISCONNECT; // Search out the "Address: " delimiter in the response wPos = TCPIP_TCP_ArrayFind(MySocket, (const uint8_t*)"Address: ", 9, 0, 0, false); // If not yet found, clear as much as possible and break if(wPos == 0xffff) { wPos = TCPIP_TCP_GetIsReady(MySocket); if(wPos > 9u) TCPIP_TCP_ArrayGet(MySocket, NULL, wPos - 9); break; } // Clear up to and past that string TCPIP_TCP_ArrayGet(MySocket, NULL, wPos + 9); // Continue on to read the IP DDnsTimer = SYS_TICK_Get(); smDDNS++; case SM_CHECKIP_FIND_ADDRESS: // Check if remote node is still connected. If not, force to the disconnect state, // but don't break because data may still be waiting. if(!TCPIP_TCP_IsConnected(MySocket) || SYS_TICK_Get() - DDnsTimer > 6*SYS_TICK_TicksPerSecondGet()) smDDNS = SM_CHECKIP_DISCONNECT; // Search out the "</body>" delimiter in the response wPos = TCPIP_TCP_ArrayFind(MySocket, (const uint8_t*)"</body>", 7, 0, 0, false); // If not yet found, break if(wPos == 0xffff) break; // Read and terminate that string as the IP address (preventing buffer overflows) if(wPos > 15u) wPos = 15; TCPIP_TCP_ArrayGet(MySocket, vBuffer, wPos); vBuffer[wPos] = '\0'; // Parse the IP address that was read, invalidating on failure if(!TCPIP_Helper_StringToIPAddress((char*)vBuffer, &ipParsed)) vBuffer[0] = '\0'; // Continue on to close the socket case SM_CHECKIP_DISCONNECT: // Close the socket TCPIP_TCP_Close(MySocket); MySocket = INVALID_SOCKET; // Determine if an update is necessary if(vBuffer[0] == '\0') {// CheckIP Failed lastStatus = DDNS_STATUS_CHECKIP_ERROR; smDDNS = SM_SOFT_ERROR; break; } if( (ipParsed.Val ==lastKnownIP.Val) && (!bForceUpdate)) { // IP address has not changed and no update is forced lastStatus = DDNS_STATUS_UNCHANGED; smDDNS = SM_DONE; break; } // Need to perform an update lastKnownIP = ipParsed; bForceUpdate = false; smDDNS++; break; case SM_IP_UPDATE_HOME: netH = TCPIP_STACK_NetDefaultGet(); if(TCPIP_DNS_UsageBegin(netH) != DNS_RES_OK) { // wait some more break; } // resolve the remote update server if(DDNSClient.ROMPointers.UpdateServer) { TCPIP_DNS_Resolve((const char*)DDNSClient.UpdateServer.szROM, DNS_TYPE_A); } else { TCPIP_DNS_Resolve((const char*)DDNSClient.UpdateServer.szRAM, DNS_TYPE_A); } smDDNS++; break; case SM_IP_UPDATE_WAIT_DNS: if(DDNSClient.ROMPointers.UpdateServer) { dnsRes = TCPIP_DNS_IsResolved((const char*)DDNSClient.UpdateServer.szROM, &ddnsUpdateIP); } else { dnsRes = TCPIP_DNS_IsResolved((const char*)DDNSClient.UpdateServer.szRAM, &ddnsUpdateIP); } if(dnsRes == DNS_RES_PENDING) { // ongoing operation; break; } TCPIP_DNS_UsageEnd(netH); if(dnsRes < 0) { // some DNS error occurred; retry later lastStatus = DDNS_STATUS_DNS_ERROR; smDDNS = SM_DNS_ERROR; break; } // update server IP solved // open the client socket to the update server MySocket = TCPIP_TCP_ClientOpen(IP_ADDRESS_TYPE_IPV4, DDNSClient.UpdatePort, (IP_MULTI_ADDRESS*)&ddnsUpdateIP); // If no socket available, try again later if(MySocket == INVALID_SOCKET) { lastStatus = DDNS_STATUS_SKT_ERROR; smDDNS = SM_SKT_ERROR; break; } // socket opened OK // Move on to the next state smDDNS++; DDnsTimer = SYS_TICK_Get(); break; case SM_IP_UPDATE_SKT_OBTAINED: // Wait for the remote server to accept our connection request if(!TCPIP_TCP_IsConnected(MySocket)) { // Time out if too much time is spent in this state if(SYS_TICK_Get() - DDnsTimer > 6*SYS_TICK_TicksPerSecondGet()) { // Close the socket so it can be used by other modules // We will try again immediately TCPIP_TCP_Close(MySocket); MySocket = INVALID_SOCKET; lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS--; } break; } // Reset timer and begin sending the request DDnsTimer = SYS_TICK_Get(); smDDNS++; // No break needed...try to send first bit immediately. case SM_IP_UPDATE_REQ_A: // Check for lost connections or timeouts if(!TCPIP_TCP_IsConnected(MySocket) || (SYS_TICK_Get() - DDnsTimer > 10*SYS_TICK_TicksPerSecondGet())) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } if(TCPIP_TCP_PutIsReady(MySocket) < 25u) // 25 =~ 16+9 break; TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"GET /nic/update?hostname="); smDDNS++; // No break needed...try to send next bit immediately. case SM_IP_UPDATE_REQ_B: // Check for lost connections or timeouts if(!TCPIP_TCP_IsConnected(MySocket) || (SYS_TICK_Get() - DDnsTimer > 10*SYS_TICK_TicksPerSecondGet())) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } // Try to write, verifying that space is available first if(DDNSClient.ROMPointers.Host) { if(TCPIP_TCP_PutIsReady(MySocket) < strlen((const char*)DDNSClient.Host.szROM)) break; TCPIP_TCP_StringPut(MySocket,DDNSClient.Host.szROM); } else { if(TCPIP_TCP_PutIsReady(MySocket) < strlen((char*)DDNSClient.Host.szRAM)) break; TCPIP_TCP_StringPut(MySocket,DDNSClient.Host.szRAM); } smDDNS++; // No break needed...try to send next bit immediately. case SM_IP_UPDATE_REQ_C: // Check for lost connections or timeouts if(!TCPIP_TCP_IsConnected(MySocket) || SYS_TICK_Get() - DDnsTimer > 10*SYS_TICK_TicksPerSecondGet()) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } if(TCPIP_TCP_PutIsReady(MySocket) < 70u) break; TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"&myip="); TCPIP_TCP_StringPut(MySocket, vBuffer); TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0"); TCPIP_TCP_Flush(MySocket); smDDNS++; // No break needed...try to send next bit immediately. case SM_IP_UPDATE_REQ_D: // Check for lost connections or timeouts if(!TCPIP_TCP_IsConnected(MySocket) || SYS_TICK_Get() - DDnsTimer > 10*SYS_TICK_TicksPerSecondGet()) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } if(TCPIP_TCP_PutIsReady(MySocket) < 131u) // 131 =~ 8+23 + dynamic dns server hostname break; TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"\r\nHost: ");//8 if(DDNSClient.ROMPointers.UpdateServer) TCPIP_TCP_StringPut(MySocket,DDNSClient.UpdateServer.szROM); else TCPIP_TCP_StringPut(MySocket,DDNSClient.UpdateServer.szRAM); TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"\r\nAuthorization: Basic ");//23 TCPIP_TCP_Flush(MySocket); smDDNS++; // No break needed...try to send the next bit immediately. case SM_IP_UPDATE_REQ_E: // Check for lost connections or timeouts if(!TCPIP_TCP_IsConnected(MySocket) || SYS_TICK_Get() - DDnsTimer > 6*SYS_TICK_TicksPerSecondGet()) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } // User name and passwords for DynDNS.org can each be up to 24 characters // Base64 encoded data is always at least 25% bigger than the original if(TCPIP_TCP_PutIsReady(MySocket) < 100u) break; if(DDNSClient.ROMPointers.Username) { ROMStrPtr = (const char*)DDNSClient.Username.szROM; wPos = strlen(ROMStrPtr); } else { RAMStrPtr = (char*)DDNSClient.Username.szRAM; wPos = strlen((char*)RAMStrPtr); } i = 0; while(wPos) { while(i < wPos && i < 3u) { if(DDNSClient.ROMPointers.Username) vBuffer[i] = *ROMStrPtr++; else vBuffer[i] = *RAMStrPtr++; i++; } wPos -= i; if(i == 3u) { TCPIP_Helper_Base64Encode(vBuffer, i, vBuffer, 4); TCPIP_TCP_ArrayPut(MySocket, vBuffer, 4); i = 0; } } if(DDNSClient.ROMPointers.Password) { ROMStrPtr = (const char*)DDNSClient.Password.szROM; wPos = strlen(ROMStrPtr); } else { RAMStrPtr = (char*)DDNSClient.Password.szRAM; wPos = strlen((char*)RAMStrPtr); } // Increment for the ':' separator and i for bytes left in username wPos += i + 1; vBuffer[i++] = ':'; while(wPos) { while(i < wPos && i < 3u) { if(DDNSClient.ROMPointers.Password) vBuffer[i] = *ROMStrPtr++; else vBuffer[i] = *RAMStrPtr++; i++; } wPos -= i; TCPIP_Helper_Base64Encode(vBuffer, i, vBuffer, 4); TCPIP_TCP_ArrayPut(MySocket, vBuffer, 4); i = 0; } TCPIP_TCP_Flush(MySocket); smDDNS++; break; case SM_IP_UPDATE_REQ_F: // Check for lost connections or timeouts if(!TCPIP_TCP_IsConnected(MySocket) || SYS_TICK_Get() - DDnsTimer > 10*SYS_TICK_TicksPerSecondGet()) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } if(TCPIP_TCP_PutIsReady(MySocket) < 50u) break; TCPIP_TCP_StringPut(MySocket, (const uint8_t*)"\r\nUser-Agent: Microchip - TCPIPSTACK - "TCPIP_STACK_VERSION"\r\n\r\n"); TCPIP_TCP_Flush(MySocket); smDDNS++; // Reset the timer to wait for a response DDnsTimer = SYS_TICK_Get(); break; case SM_IPUPDATE_FIND_RESPONSE: // Locate the response string // Wait up to 10 seconds for a response if(SYS_TICK_Get() - DDnsTimer > 10*SYS_TICK_TicksPerSecondGet()) { lastStatus = DDNS_STATUS_UPDATE_ERROR; smDDNS = SM_IPUDATE_DISCONNECT; break; } // According to HTTP, the response will start after the two CRLFs wPos = TCPIP_TCP_ArrayFind(MySocket, (const uint8_t*)"\r\n\r\n", 4, 0, 0, false); // If not yet found, eliminate everything up to if(wPos == 0xffff) { wPos = TCPIP_TCP_GetIsReady(MySocket); if(wPos > 4u) TCPIP_TCP_ArrayGet(MySocket, NULL, wPos - 4); break; } TCPIP_TCP_ArrayGet(MySocket, NULL, wPos+4); smDDNS++; // No break...continue to next state immediately case SM_IPUPDATE_PARSE_RESPONSE: // Try to parse the response text // Wait up to 10 seconds for the remote server to disconnect // so we know all data has been received if(TCPIP_TCP_IsConnected(MySocket) && SYS_TICK_Get() - DDnsTimer < 10*SYS_TICK_TicksPerSecondGet()) break; // Read the response code wPos = TCPIP_TCP_GetIsReady(MySocket); if(wPos > sizeof(vBuffer) - 1) wPos = sizeof(vBuffer) - 1; wPos = TCPIP_TCP_ArrayGet(MySocket, vBuffer, wPos); vBuffer[wPos] = '\0'; for(i = 0; i < sizeof(vBuffer); i++) if(vBuffer[i] == ' ') vBuffer[i] = '\0'; for(lastStatus = 0; lastStatus < DDNS_STATUS_UPDATE_ERROR; lastStatus++) if(!strcmp((char*)vBuffer, (const char*)_updateIpSrvrResponse[lastStatus])) break; smDDNS++; // No break...continue to finalization case SM_IPUDATE_DISCONNECT: // Close the socket so it can be used by other modules. if(MySocket != INVALID_SOCKET) { TCPIP_TCP_Close(MySocket); MySocket = INVALID_SOCKET; } // Determine what to do based on status if(lastStatus <= DDNS_STATUS_NUMHOST || lastStatus == DDNS_STATUS_UNCHANGED) smDDNS = SM_DONE; else if(lastStatus == DDNS_STATUS_911 || lastStatus == DDNS_STATUS_DNSERR) smDDNS = SM_SYSTEM_ERROR; else smDDNS = SM_SOFT_ERROR; smDDNS++; break; case SM_DONE: dwUpdateAt = SYS_TICK_Get() + 10*60*SYS_TICK_TicksPerSecondGet(); // 10 minutes smDDNS = SM_IDLE; break; case SM_SOFT_ERROR: case SM_DNS_ERROR: case SM_SKT_ERROR: dwUpdateAt = SYS_TICK_Get() + 30*SYS_TICK_TicksPerSecondGet(); // 30 seconds smDDNS = SM_IDLE; break; case SM_SYSTEM_ERROR: dwUpdateAt = SYS_TICK_Get() + 30*60*SYS_TICK_TicksPerSecondGet(); // 30 minutes smDDNS = SM_IDLE; break; } }