/***************************************************************************** Function: void SMTPTask(void) Summary: Performs any pending SMTP client tasks Description: This function handles periodic tasks associated with the SMTP client, such as processing initial connections and command sequences. Precondition: None Parameters: None Returns: None Remarks: This function acts as a task (similar to one in an RTOS). It performs its task in a co-operative manner, and the main application must call this function repeatedly to ensure that all open or new connections are served in a timely fashion. ***************************************************************************/ void SMTPTask(void) { BYTE i; WORD w; BYTE vBase64Buffer[4]; static DWORD Timer; static BYTE RXBuffer[4]; static ROM BYTE *ROMStrPtr, *ROMStrPtr2; static BYTE *RAMStrPtr; static WORD wAddressLength; WORD tmp; switch(TransportState) { case TRANSPORT_HOME: // SMTPBeginUsage() 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 SMTPSendMail() if(!SMTPFlags.bits.ReadyToStart) break; // Obtain ownership of the DNS resolution module if(!DNSBeginUsage()) break; // Obtain the IP address associated with the SMTP mail server if(SMTPClient.Server.szRAM || SMTPClient.Server.szROM) { if(SMTPClient.ROMPointers.Server) DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_A); else DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_A); } else { // If we don't have a mail server, try to send the mail // directly to the destination SMTP server if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To) { SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.To.szRAM, '@'); SMTPClient.ROMPointers.Server = 0; } else if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To) { SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.To.szROM, '@'); SMTPClient.ROMPointers.Server = 1; } if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM)) { if(SMTPClient.CC.szRAM && !SMTPClient.ROMPointers.CC) { SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.CC.szRAM, '@'); SMTPClient.ROMPointers.Server = 0; } else if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC) { SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.CC.szROM, '@'); SMTPClient.ROMPointers.Server = 1; } } if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM)) { if(SMTPClient.BCC.szRAM && !SMTPClient.ROMPointers.BCC) { SMTPClient.Server.szRAM = (BYTE*)strchr((char*)SMTPClient.BCC.szRAM, '@'); SMTPClient.ROMPointers.Server = 0; } else if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC) { SMTPClient.Server.szROM = (ROM BYTE*)strchrpgm((ROM char*)SMTPClient.BCC.szROM, '@'); SMTPClient.ROMPointers.Server = 1; } } // See if we found a hostname anywhere which we could resolve if(!(SMTPClient.Server.szRAM || SMTPClient.Server.szROM)) { DNSEndUsage(); ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; break; } // Skip over the @ sign and resolve the host name if(SMTPClient.ROMPointers.Server) { SMTPClient.Server.szROM++; DNSResolveROM(SMTPClient.Server.szROM, DNS_TYPE_MX); } else { SMTPClient.Server.szRAM++; DNSResolve(SMTPClient.Server.szRAM, DNS_TYPE_MX); } } Timer = TickGet(); TransportState++; break; case TRANSPORT_NAME_RESOLVE: // Wait for the DNS server to return the requested IP address if(!DNSIsResolved(&SMTPServer)) { // Timeout after 6 seconds of unsuccessful DNS resolution if(TickGet() - Timer > 6*TICK_SECOND) { ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; DNSEndUsage(); } 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. ResponseCode = SMTP_RESOLVE_ERROR; TransportState = TRANSPORT_HOME; break; } TransportState++; // No need to break here case TRANSPORT_OBTAIN_SOCKET: // Connect a TCP socket to the remote SMTP server MySocket = TCPOpen(SMTPServer.Val, TCP_OPEN_IP_ADDRESS, SMTPClient.ServerPort, TCP_PURPOSE_DEFAULT); // Abort operation if no TCP sockets are available // If this ever happens, add some more // TCP_PURPOSE_DEFAULT sockets in TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; TransportState++; Timer = TickGet(); // No break; fall into TRANSPORT_SOCKET_OBTAINED #if defined(STACK_USE_SSL_CLIENT) case TRANSPORT_SECURING_SOCKET: if(!TCPIsConnected(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((LONG)(TickGet()-Timer) > (LONG)(SMTP_SERVER_REPLY_TIMEOUT)) { ResponseCode = SMTP_CONNECT_ERROR; TransportState = TRANSPORT_CLOSE; } break; } SMTPFlags.bits.ConnectedOnce = TRUE; // Start SSL if needed for this connection if(SMTPClient.UseSSL && !TCPStartSSLClient(MySocket,NULL)) break; // Move on to main state Timer = TickGet(); TransportState++; break; #endif case TRANSPORT_SOCKET_OBTAINED: if(!TCPIsConnected(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 || ((LONG)(TickGet()-Timer) > (LONG)(SMTP_SERVER_REPLY_TIMEOUT))) { ResponseCode = SMTP_CONNECT_ERROR; TransportState = TRANSPORT_CLOSE; } break; } SMTPFlags.bits.ConnectedOnce = TRUE; #if defined(STACK_USE_SSL_CLIENT) // Make sure the SSL handshake has completed if(SMTPClient.UseSSL && TCPSSLIsHandshaking(MySocket)) break; #endif // See if the server sent us anything while(TCPIsGetReady(MySocket)) { TCPGet(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.szRAM || SMTPClient.Username.szROM) 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: tmp = SMTPState; 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(TCPIsPutReady(MySocket) < 64u) break; switch(SMTPState) { case SMTP_HELO: if(SMTPClient.Username.szROM == NULL) TCPPutROMString(MySocket, (ROM BYTE*)"HELO MCHPBOARD\r\n"); else TCPPutROMString(MySocket, (ROM BYTE*)"EHLO MCHPBOARD\r\n"); TCPFlush(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 (either SMTPClient.Username.szROM or // SMTPClient.Username.szRAM is non-NULL) TCPPutROMString(MySocket, (ROM BYTE*)"AUTH LOGIN\r\n"); TCPFlush(MySocket); SMTPState++; break; case SMTP_AUTH_USERNAME: // Base 64 encode and transmit the username. if(SMTPClient.ROMPointers.Username) { ROMStrPtr = SMTPClient.Username.szROM; w = strlenpgm((ROM char*)ROMStrPtr); } else { RAMStrPtr = SMTPClient.Username.szRAM; w = strlen((char*)RAMStrPtr); } while(w) { i = 0; while((i < w) && (i < sizeof(vBase64Buffer)*3/4)) { if(SMTPClient.ROMPointers.Username) vBase64Buffer[i] = *ROMStrPtr++; else vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer)); TCPPutArray(MySocket, vBase64Buffer, sizeof(vBase64Buffer)); } TCPPutROMString(MySocket, (ROM BYTE*)"\r\n"); TCPFlush(MySocket); SMTPState++; break; case SMTP_AUTH_PASSWORD: // Base 64 encode and transmit the password if(SMTPClient.ROMPointers.Password) { ROMStrPtr = SMTPClient.Password.szROM; w = strlenpgm((ROM char*)ROMStrPtr); } else { RAMStrPtr = SMTPClient.Password.szRAM; w = strlen((char*)RAMStrPtr); } while(w) { i = 0; while((i < w) && (i < sizeof(vBase64Buffer)*3/4)) { if(SMTPClient.ROMPointers.Password) vBase64Buffer[i] = *ROMStrPtr++; else vBase64Buffer[i] = *RAMStrPtr++; i++; } w -= i; Base64Encode(vBase64Buffer, i, vBase64Buffer, sizeof(vBase64Buffer)); TCPPutArray(MySocket, vBase64Buffer, sizeof(vBase64Buffer)); } TCPPutROMString(MySocket, (ROM BYTE*)"\r\n"); TCPFlush(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. TCPPutROMString(MySocket, (ROM BYTE*)"MAIL FROM:<"); if(SMTPClient.ROMPointers.From) { ROMStrPtr = FindROMEmailAddress(SMTPClient.From.szROM, &wAddressLength); TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength); } else { RAMStrPtr = FindEmailAddress(SMTPClient.From.szRAM, &wAddressLength); TCPPutArray(MySocket, RAMStrPtr, wAddressLength); } TCPPutROMString(MySocket, (ROM BYTE*)">\r\n"); TCPFlush(MySocket); SMTPState++; break; case SMTP_RCPTTO_INIT: // See if there are any (To) recipients to process if(SMTPClient.To.szRAM && !SMTPClient.ROMPointers.To) { RAMStrPtr = FindEmailAddress(SMTPClient.To.szRAM, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTO; break; } } if(SMTPClient.To.szROM && SMTPClient.ROMPointers.To) { ROMStrPtr = FindROMEmailAddress(SMTPClient.To.szROM, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTO; break; } } SMTPState = SMTP_RCPTTOCC_INIT; break; case SMTP_RCPTTO: case SMTP_RCPTTOCC: case SMTP_RCPTTOBCC: TCPPutROMString(MySocket, (ROM BYTE*)"RCPT TO:<"); if( (SMTPClient.ROMPointers.To && (SMTPState == SMTP_RCPTTO)) || (SMTPClient.ROMPointers.CC && (SMTPState == SMTP_RCPTTOCC)) || (SMTPClient.ROMPointers.BCC && (SMTPState == SMTP_RCPTTOBCC)) ) TCPPutROMArray(MySocket, ROMStrPtr, wAddressLength); else TCPPutArray(MySocket, RAMStrPtr, wAddressLength); TCPPutROMString(MySocket, (ROM BYTE*)">\r\n"); TCPFlush(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 if(SMTPClient.ROMPointers.To) ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength); else 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.szRAM && !SMTPClient.ROMPointers.CC) { RAMStrPtr = FindEmailAddress(SMTPClient.CC.szRAM, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOCC; break; } } if(SMTPClient.CC.szROM && SMTPClient.ROMPointers.CC) { ROMStrPtr = FindROMEmailAddress(SMTPClient.CC.szROM, &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 if(SMTPClient.ROMPointers.CC) ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength); else 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.szRAM && !SMTPClient.ROMPointers.BCC) { RAMStrPtr = FindEmailAddress(SMTPClient.BCC.szRAM, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOBCC; break; } } if(SMTPClient.BCC.szROM && SMTPClient.ROMPointers.BCC) { ROMStrPtr = FindROMEmailAddress(SMTPClient.BCC.szROM, &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 if(SMTPClient.ROMPointers.BCC) ROMStrPtr = FindROMEmailAddress(ROMStrPtr+wAddressLength, &wAddressLength); else RAMStrPtr = FindEmailAddress(RAMStrPtr+wAddressLength, &wAddressLength); if(wAddressLength) { SMTPState = SMTP_RCPTTOBCC; break; } // All done with BCC field SMTPState++; //No break case SMTP_DATA: TCPPutROMString(MySocket, (ROM BYTE*)"DATA\r\n"); SMTPState++; PutHeadersState = PUTHEADERS_FROM_INIT; TCPFlush(MySocket); break; case SMTP_DATA_HEADER: while((PutHeadersState != PUTHEADERS_DONE) && (TCPIsPutReady(MySocket) > 64u)) { switch(PutHeadersState) { case PUTHEADERS_FROM_INIT: if(SMTPClient.From.szRAM || SMTPClient.From.szROM) { PutHeadersState = PUTHEADERS_FROM; TCPPutROMString(MySocket, (ROM BYTE*)"From: "); } else { PutHeadersState = PUTHEADERS_TO_INIT; } break; case PUTHEADERS_FROM: if(SMTPClient.ROMPointers.From) { SMTPClient.From.szROM = TCPPutROMString(MySocket, SMTPClient.From.szROM); if(*SMTPClient.From.szROM == 0u) PutHeadersState = PUTHEADERS_TO_INIT; } else { SMTPClient.From.szRAM = TCPPutString(MySocket, SMTPClient.From.szRAM); if(*SMTPClient.From.szRAM == 0u) PutHeadersState = PUTHEADERS_TO_INIT; } break; case PUTHEADERS_TO_INIT: if(SMTPClient.To.szRAM || SMTPClient.To.szROM) { PutHeadersState = PUTHEADERS_TO; TCPPutROMString(MySocket, (ROM BYTE*)"\r\nTo: "); } else { PutHeadersState = PUTHEADERS_CC_INIT; } break; case PUTHEADERS_TO: if(SMTPClient.ROMPointers.To) { SMTPClient.To.szROM = TCPPutROMString(MySocket, SMTPClient.To.szROM); if(*SMTPClient.To.szROM == 0u) PutHeadersState = PUTHEADERS_CC_INIT; } else { SMTPClient.To.szRAM = TCPPutString(MySocket, SMTPClient.To.szRAM); if(*SMTPClient.To.szRAM == 0u) PutHeadersState = PUTHEADERS_CC_INIT; } break; case PUTHEADERS_CC_INIT: if(SMTPClient.CC.szRAM || SMTPClient.CC.szROM) { PutHeadersState = PUTHEADERS_CC; TCPPutROMString(MySocket, (ROM BYTE*)"\r\nCC: "); } else { PutHeadersState = PUTHEADERS_SUBJECT_INIT; } break; case PUTHEADERS_CC: if(SMTPClient.ROMPointers.CC) { SMTPClient.CC.szROM = TCPPutROMString(MySocket, SMTPClient.CC.szROM); if(*SMTPClient.CC.szROM == 0u) PutHeadersState = PUTHEADERS_SUBJECT_INIT; } else { SMTPClient.CC.szRAM = TCPPutString(MySocket, SMTPClient.CC.szRAM); if(*SMTPClient.CC.szRAM == 0u) PutHeadersState = PUTHEADERS_SUBJECT_INIT; } break; case PUTHEADERS_SUBJECT_INIT: if(SMTPClient.Subject.szRAM || SMTPClient.Subject.szROM) { PutHeadersState = PUTHEADERS_SUBJECT; TCPPutROMString(MySocket, (ROM BYTE*)"\r\nSubject: "); } else { PutHeadersState = PUTHEADERS_OTHER_INIT; } break; case PUTHEADERS_SUBJECT: if(SMTPClient.ROMPointers.Subject) { SMTPClient.Subject.szROM = TCPPutROMString(MySocket, SMTPClient.Subject.szROM); if(*SMTPClient.Subject.szROM == 0u) PutHeadersState = PUTHEADERS_OTHER_INIT; } else { SMTPClient.Subject.szRAM = TCPPutString(MySocket, SMTPClient.Subject.szRAM); if(*SMTPClient.Subject.szRAM == 0u) PutHeadersState = PUTHEADERS_OTHER_INIT; } break; case PUTHEADERS_OTHER_INIT: TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2); if(SMTPClient.OtherHeaders.szRAM || SMTPClient.OtherHeaders.szROM) { PutHeadersState = PUTHEADERS_OTHER; } else { TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } break; case PUTHEADERS_OTHER: if(SMTPClient.ROMPointers.OtherHeaders) { SMTPClient.OtherHeaders.szROM = TCPPutROMString(MySocket, SMTPClient.OtherHeaders.szROM); if(*SMTPClient.OtherHeaders.szROM == 0u) { TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } } else { SMTPClient.OtherHeaders.szRAM = TCPPutString(MySocket, SMTPClient.OtherHeaders.szRAM); if(*SMTPClient.OtherHeaders.szRAM == 0u) { TCPPutROMArray(MySocket, (ROM BYTE*)"\r\n", 2); PutHeadersState = PUTHEADERS_DONE; SMTPState++; } } break; // Default case needed to supress compiler diagnostics default: break; } } TCPFlush(MySocket); break; case SMTP_DATA_BODY_INIT: SMTPState++; RAMStrPtr = SMTPClient.Body.szRAM; ROMStrPtr2 = (ROM BYTE*)"\r\n.\r\n"; CRPeriod.Pos = NULL; if(RAMStrPtr) CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM char*)"\r\n."); // No break here case SMTP_DATA_BODY: if(SMTPClient.Body.szRAM || SMTPClient.Body.szROM) { if(*ROMStrPtr2) { // Put the application data, doing the transparancy replacement of "\r\n." with "\r\n.." while(CRPeriod.Pos) { CRPeriod.Pos += 3; RAMStrPtr += TCPPutArray(MySocket, RAMStrPtr, CRPeriod.Pos-RAMStrPtr); if(RAMStrPtr == CRPeriod.Pos) { if(!TCPPut(MySocket, '.')) { CRPeriod.Pos -= 3; break; } } else { CRPeriod.Pos -= 3; break; } CRPeriod.Pos = (BYTE*)strstrrampgm((char*)RAMStrPtr, (ROM 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 = TCPPutString(MySocket, RAMStrPtr); ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2); TCPFlush(MySocket); } } else { if(SMTPFlags.bits.ReadyToFinish) { if(*ROMStrPtr2) { ROMStrPtr2 = TCPPutROMString(MySocket, ROMStrPtr2); TCPFlush(MySocket); } } } if(*ROMStrPtr2 == 0u) { SMTPState++; } break; case SMTP_QUIT_INIT: SMTPState++; ROMStrPtr = (ROM BYTE*)"QUIT\r\n"; // No break here case SMTP_QUIT: if(*ROMStrPtr) { ROMStrPtr = TCPPutROMString(MySocket, ROMStrPtr); TCPFlush(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 TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; // Go back to doing nothing TransportState = TRANSPORT_HOME; break; } }
void TCPTXPerformanceTask(void) { static TCP_SOCKET MySocket = INVALID_SOCKET; static DWORD dwTimeStart; static DWORD dwBytesSent; static DWORD_VAL dwVLine; BYTE vBuffer[10]; static BYTE vBytesPerSecond[12]; WORD w; DWORD dw; QWORD qw; // Start the TCP server, listening on PERFORMANCE_PORT if(MySocket == INVALID_SOCKET) { MySocket = TCPOpen(0, TCP_OPEN_SERVER, TX_PERFORMANCE_PORT, TCP_PURPOSE_TCP_PERFORMANCE_TX); // Abort operation if no TCP socket of type TCP_PURPOSE_TCP_PERFORMANCE_TEST is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) return; dwVLine.Val = 0; dwTimeStart = TickGet(); vBytesPerSecond[0] = 0; // Initialize empty string right now dwBytesSent = 0; } // See how many bytes we can write to the TX FIFO // If we can't fit a single line of data in, then // lets just wait for now. w = TCPIsPutReady(MySocket); if(w < 12+27+5+32u) return; vBuffer[0] = '0'; vBuffer[1] = 'x'; // Transmit as much data as the TX FIFO will allow while(w >= 12+27+5+32u) { // Convert line counter to ASCII hex string vBuffer[2] = btohexa_high(dwVLine.v[3]); vBuffer[3] = btohexa_low(dwVLine.v[3]); vBuffer[4] = btohexa_high(dwVLine.v[2]); vBuffer[5] = btohexa_low(dwVLine.v[2]); vBuffer[6] = btohexa_high(dwVLine.v[1]); vBuffer[7] = btohexa_low(dwVLine.v[1]); vBuffer[8] = btohexa_high(dwVLine.v[0]); vBuffer[9] = btohexa_low(dwVLine.v[0]); dwVLine.Val++; // Place all data in the TCP TX FIFO TCPPutArray(MySocket, vBuffer, sizeof(vBuffer)); dw = TickGet() - dwTimeStart; // Calculate exact bytes/second, less truncation if((dwVLine.v[0] & 0x3F) == 0x00) { qw = (QWORD)dwBytesSent * (TICK_SECOND/100); qw /= dw; ultoa((DWORD)qw, vBytesPerSecond); } TCPPutROMString(MySocket, (ROM BYTE*)": We are currently achieving "); TCPPutROMArray(MySocket, (ROM BYTE*)" ", 5-strlen((char*)vBytesPerSecond)); TCPPutString(MySocket, vBytesPerSecond); TCPPutROMString(MySocket, (ROM BYTE*)"00 bytes/second TX throughput.\r\n"); if(dw > TICK_SECOND) { dwBytesSent >>= 1; dwTimeStart += dw>>1; } w -= 12+27+5+32; dwBytesSent += 12+27+5+32; }
static void HTTPProcess(HTTP_HANDLE h) { char bafs[26], r; BOOL lbContinue; static HTTP_INFO* ph; WORD w; static BYTE *p, *t; ph = &HCB[h]; do { lbContinue = FALSE; if(!TCPIsConnected(ph->socket)) { ph->smHTTP = SM_HTTP_IDLE; break; } switch(ph->smHTTP) { case SM_HTTP_IDLE: w = TCPGetArray(ph->socket, httpData, MAX_HTML_CMD_LEN); if(!w) { if(TCPGetRxFIFOFree(ph->socket) == 0) TCPDisconnect(ph->socket); // Request is too big, we can't support it. break; } httpData[w] = 0; t = p = httpData; while(*p) if(*p=='%') { *t++ = hex2bin(p+1); p += 3; } else *t++ = *p++; *t = 0; r = httpData[150]; httpData[150]=0; lbContinue = TRUE; ph->smHTTP = SM_HTTP_NOT_FOUND; if(strstrrampgm(httpData,"POST")) ph->smHTTP = SM_HTTP_POST; if(strstrrampgm(httpData,"GET")) { ph->smHTTP = SM_HTTP_HEADER; #ifndef _FAVICON_ if(strstrrampgm(httpData,(ROM void*)"favicon")) { TCPDisconnect(ph->socket); ph->smHTTP = SM_HTTP_IDLE; } #else if(strstrrampgm(httpData,"favicon")) ph->smHTTP = SM_ICO_HEADER; #endif if(strstrrampgm(httpData, "Sw_Pool")) AppConfig.who ^= 0x81; if(strstrrampgm(httpData, "Sw_Mode")) AppConfig.sw_mode ^= 1; if(strstrrampgm(httpData, "Sw_Clock")) AppConfig.CkSel ^= 1; if(strstrrampgm(httpData, "Sw_LEDs")) bLEDs ^= 1; } httpData[150]=r; break; case SM_HTTP_POST: exoit(ph->socket); memcpypgm2ram(spwrk,rMinPool,SZ_ROMS ); for(r=0;r<SZ_SRCH;r++) { BYTE *s; p = strstrrampgm(httpData,(ROM BYTE*)(DWORD)sComa[r]); if(p) { p+=5; t=strstrrampgm(p,ampa); if(t) { *t=0; s=p; switch(r) { // case C_JMAC: Hex2Mac(p); break; //S2Mac(p); break; case C_JMIP: StringToIPAddress(p,&AppConfig.MyIPAddr); break; case C_JMSK: StringToIPAddress(p,&AppConfig.MyMask); break; case C_JGTW: StringToIPAddress(p,&AppConfig.MyGateway); break; case C_PDNS: StringToIPAddress(p,&AppConfig.PrimaryDNSServer); break; case C_SDNS: StringToIPAddress(p,&AppConfig.SecondaryDNSServer); break; case C_WPRT: AppConfig.MyPort = atoi(p); break; case C_MPRT: while(*p) if((*p) == ',') { *p=0; AppConfig.MinPort[0] = atoi(s); break; } else p++; AppConfig.MinPort[1] = atoi(++p); *--p = ','; break; case C_MURL: while(*p) if((*p) == ',') { *p=0; strcpy(&spwrk[0],s); break; } else p++; strcpy(&spwrk[sizeof(rMinPool)/2],++p); *--p = ','; break; case C_USPA: while(*p) if((*p) == ',') { *p=0; strcpy(&spwrk[sizeof(rMinPool)],s); break; } else p++; strcpy(&spwrk[sizeof(rMinPool)+sizeof(rUsrPass)/2],++p); *--p = ','; break; } *t='&'; } } } ph->smHTTP = SM_HTTP_IDLE; SetUPS(); break; case SM_HTTP_NOT_FOUND: if(TCPIsPutReady(ph->socket) >= sizeof(hdrErr)) { TCPPutROMString(ph->socket, hdrErr); TCPFlush(ph->socket); TCPDisconnect(ph->socket); ph->smHTTP = SM_HTTP_IDLE; } break; #ifdef _FAVICON_ case SM_ICO_HEADER: if ( TCPIsPutReady(ph->socket) ) { lbContinue = TRUE; if(TCPIsPutReady(ph->socket) >= sizeof(hdrICO)+198) { TCPPutROMString(ph->socket, hdrICO); TCPPutROMArray(ph->socket, favicon,198); TCPFlush(ph->socket); TCPDisconnect(ph->socket); ph->smHTTP = SM_HTTP_IDLE; } } break; #endif case SM_HTTP_HEADER: if ( TCPIsPutReady(ph->socket) ) { lbContinue = TRUE; if(TCPIsPutReady(ph->socket) >= sizeof(hdrOK)) { TCPPutROMString(ph->socket, hdrOK); TCPFlush(ph->socket); ph->smHTTP = SM_HTTP_GET; ph->Pos = Page; } } break; case SM_HTTP_GET: TCPDiscard(ph->socket); if(TCPIsPutReady(ph->socket) >= 400) { ph->Pos = TCPPutROMString(ph->socket, ph->Pos); ph->Pos++; switch (*ph->Pos) { case 0: TCPDisconnect(ph->socket); ph->smHTTP = SM_HTTP_IDLE; ph->Pos = Page; break; case 1: DoStic(ph->socket, 1); break; case 2: DoStic(ph->socket, 2); break; case 3: DoStic(ph->socket, 3); break; // case 4: MAC2Hex(bafs); TCPPutString(ph->socket, bafs); break; case 5: IP2String(AppConfig.MyIPAddr,bafs); TCPPutString(ph->socket, bafs); break; case 6: IP2String(AppConfig.MyMask,bafs); TCPPutString(ph->socket, bafs); break; case 7: IP2String(AppConfig.MyGateway,bafs); TCPPutString(ph->socket, bafs); break; case 8: uitoa(AppConfig.MyPort,bafs); TCPPutString(ph->socket, bafs); break; case 9: IP2String(AppConfig.PrimaryDNSServer,bafs); TCPPutString(ph->socket, bafs); break; case 10: IP2String(AppConfig.SecondaryDNSServer,bafs); TCPPutString(ph->socket, bafs); break; case 11: uitoa(AppConfig.MinPort[0],bafs); TCPPutString(ph->socket, bafs); TCPPut(ph->socket,','); uitoa(AppConfig.MinPort[1],bafs); TCPPutString(ph->socket, bafs); break; case 12: TCPPutROMString(ph->socket, rMinPool[0]); TCPPut(ph->socket,','); TCPPutROMString(ph->socket, rMinPool[1]); break; case 13: TCPPutROMString(ph->socket, rUsrPass[0]); TCPPut(ph->socket,','); TCPPutROMString(ph->socket, rUsrPass[1]); break; } ph->Pos++; } TCPFlush(ph->socket); break; default: break; } } while( lbContinue ); }
/********************************************************************* * Function: void TelnetTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void TelnetTask(void) { BYTE i; BYTE vTelnetSession; WORD w, w2; TCP_SOCKET MySocket; enum { SM_HOME = 0, SM_PRINT_LOGIN, SM_GET_LOGIN, SM_GET_PASSWORD, SM_GET_PASSWORD_BAD_LOGIN, SM_AUTHENTICATED, SM_REFRESH_VALUES } TelnetState; static TCP_SOCKET hTelnetSockets[MAX_TELNET_CONNECTIONS]; static BYTE vTelnetStates[MAX_TELNET_CONNECTIONS]; static BOOL bInitialized = FALSE; // Perform one time initialization on power up if(!bInitialized) { for(vTelnetSession = 0; vTelnetSession < MAX_TELNET_CONNECTIONS; vTelnetSession++) { hTelnetSockets[vTelnetSession] = INVALID_SOCKET; vTelnetStates[vTelnetSession] = SM_HOME; } bInitialized = TRUE; } // Loop through each telnet session and process state changes and TX/RX data for(vTelnetSession = 0; vTelnetSession < MAX_TELNET_CONNECTIONS; vTelnetSession++) { // Load up static state information for this session MySocket = hTelnetSockets[vTelnetSession]; TelnetState = vTelnetStates[vTelnetSession]; // Reset our state if the remote client disconnected from us if(MySocket != INVALID_SOCKET) { if(TCPWasReset(MySocket)) TelnetState = SM_PRINT_LOGIN; } // Handle session state switch(TelnetState) { case SM_HOME: // Connect a socket to the remote TCP server MySocket = TCPOpen(0, TCP_OPEN_SERVER, TELNET_PORT, TCP_PURPOSE_TELNET); // Abort operation if no TCP socket of type TCP_PURPOSE_TELNET is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; TelnetState++; break; case SM_PRINT_LOGIN: // Make certain the socket can be written to if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strTitle)) break; // Place the application protocol data into the transmit buffer. TCPPutROMString(MySocket, strTitle); // Send the packet TCPFlush(MySocket); TelnetState++; case SM_GET_LOGIN: // Make sure we can put the password prompt if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strPassword)) break; // See if the user pressed return w = TCPFind(MySocket, '\n', 0, FALSE); if(w == 0xFFFFu) { if(TCPGetRxFIFOFree(MySocket) == 0u) { TCPPutROMString(MySocket, (ROM BYTE*)"\r\nToo much data.\r\n"); TCPDisconnect(MySocket); } break; } // Search for the username -- case insensitive w2 = TCPFindROMArray(MySocket, (ROM BYTE*)TELNET_USERNAME, sizeof(TELNET_USERNAME)-1, 0, TRUE); if((w2 != 0u) || !((sizeof(TELNET_USERNAME)-1 == w) || (sizeof(TELNET_USERNAME) == w))) { // Did not find the username, but let's pretend we did so we don't leak the user name validity TelnetState = SM_GET_PASSWORD_BAD_LOGIN; } else { TelnetState = SM_GET_PASSWORD; } // Username verified, throw this line of data away TCPGetArray(MySocket, NULL, w + 1); // Print the password prompt TCPPutROMString(MySocket, strPassword); TCPFlush(MySocket); break; case SM_GET_PASSWORD: case SM_GET_PASSWORD_BAD_LOGIN: // Make sure we can put the authenticated prompt if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strAuthenticated)) break; // See if the user pressed return w = TCPFind(MySocket, '\n', 0, FALSE); if(w == 0xFFFFu) { if(TCPGetRxFIFOFree(MySocket) == 0u) { TCPPutROMString(MySocket, (ROM BYTE*)"Too much data.\r\n"); TCPDisconnect(MySocket); } break; } // Search for the password -- case sensitive w2 = TCPFindROMArray(MySocket, (ROM BYTE*)TELNET_PASSWORD, sizeof(TELNET_PASSWORD)-1, 0, FALSE); if((w2 != 3u) || !((sizeof(TELNET_PASSWORD)-1 == w-3) || (sizeof(TELNET_PASSWORD) == w-3)) || (TelnetState == SM_GET_PASSWORD_BAD_LOGIN)) { // Did not find the password TelnetState = SM_PRINT_LOGIN; TCPPutROMString(MySocket, strAccessDenied); TCPDisconnect(MySocket); break; } // Password verified, throw this line of data away TCPGetArray(MySocket, NULL, w + 1); // Print the authenticated prompt TCPPutROMString(MySocket, strAuthenticated); TelnetState = SM_AUTHENTICATED; // No break case SM_AUTHENTICATED: if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strDisplay) + 4) break; TCPPutROMString(MySocket, strDisplay); TelnetState++; // All future characters will be bold TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[1m"); case SM_REFRESH_VALUES: if(TCPIsPutReady(MySocket) >= 78u) { //[10;1] //"SNTP Time: (disabled)\r\n" //"Analog: 1023\r\n" //"Buttons: 3 2 1 0\r\n" //"LEDs: 7 6 5 4 3 2 1 0\r\n" // Write current UTC seconds from SNTP module, if it is enable // and has changed. Note that conversion from a DWORD to an // ASCII string can take a lot of CPU power, so we only print // this if the value has changed. #if defined(STACK_USE_SNTP_CLIENT) { static DWORD dwTime; BYTE vTime[11]; if(dwTime != SNTPGetUTCSeconds()) { // Position cursor at Line 10, Col 15 TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[10;15f"); dwTime = SNTPGetUTCSeconds(); ultoa(dwTime, vTime); TCPPutROMArray(MySocket, (ROM BYTE*)strSpaces, 10-strlen((char*)vTime)); TCPPutString(MySocket, vTime); } } #endif // Position cursor at Line 11, Col 21 TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[11;21f"); // Put analog value with space padding on right side for 4 characters TCPPutROMArray(MySocket, (ROM BYTE*)strSpaces, 4-strlen((char*)AN0String)); TCPPutString(MySocket, AN0String); // Put Buttons TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[12;18f"); TCPPut(MySocket, BUTTON3_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, BUTTON2_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, BUTTON1_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, BUTTON0_IO ? '1':'0'); // Put LEDs TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[13;10f"); TCPPut(MySocket, LED1_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED0_IO ? '1':'0'); // Put cursor at beginning of next line TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[14;1f"); // Send the data out immediately TCPFlush(MySocket); } if(TCPIsGetReady(MySocket)) { TCPGet(MySocket, &i); switch(i) { case '\r': case 'q': case 'Q': if(TCPIsPutReady(MySocket) >= strlenpgm((ROM char*)strGoodBye)) TCPPutROMString(MySocket, strGoodBye); TCPDisconnect(MySocket); TelnetState = SM_PRINT_LOGIN; break; } } break; } // Save session state back into the static array hTelnetSockets[vTelnetSession] = MySocket; vTelnetStates[vTelnetSession] = TelnetState; } }
/********************************************************************* * Function: void TelnetTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void TelnetTask(void) { BYTE i; WORD w, w2; static TCP_SOCKET MySocket = INVALID_SOCKET; static enum _TelnetState { SM_HOME = 0, SM_PRINT_LOGIN, SM_GET_LOGIN, SM_GET_PASSWORD, SM_GET_PASSWORD_BAD_LOGIN, SM_AUTHENTICATED, SM_REFRESH_VALUES, } TelnetState = SM_HOME; // Reset our state if the remote client disconnected from us if(MySocket != INVALID_SOCKET) { if(TCPWasReset(MySocket)) TelnetState = SM_PRINT_LOGIN; } switch(TelnetState) { case SM_HOME: // Connect a socket to the remote TCP server MySocket = TCPOpen(0, TCP_OPEN_SERVER, TELNET_PORT, TCP_PURPOSE_TELNET); // Abort operation if no TCP socket of type TCP_PURPOSE_TELNET is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; TelnetState++; break; case SM_PRINT_LOGIN: // Make certain the socket can be written to if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strTitle)) break; // Place the application protocol data into the transmit buffer. TCPPutROMString(MySocket, strTitle); // Send the packet TCPFlush(MySocket); TelnetState++; case SM_GET_LOGIN: // Make sure we can put the password prompt if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strPassword)) break; // See if the user pressed return w = TCPFind(MySocket, '\n', 0, FALSE); if(w == 0xFFFFu) { if(TCPGetRxFIFOFree(MySocket) == 0u) { TCPPutROMString(MySocket, (ROM BYTE*)"\r\nToo much data.\r\n"); TCPDisconnect(MySocket); } break; } // Search for the username -- case insensitive w2 = TCPFindROMArray(MySocket, (ROM BYTE*)USERNAME, sizeof(USERNAME)-1, 0, TRUE); if((w2 != 0) || !((sizeof(USERNAME)-1 == w) || (sizeof(USERNAME) == w))) { // Did not find the username, but let's pretend we did so we don't leak the user name validity TelnetState = SM_GET_PASSWORD_BAD_LOGIN; } else { TelnetState = SM_GET_PASSWORD; } // Username verified, throw this line of data away TCPGetArray(MySocket, NULL, w + 1); // Print the password prompt TCPPutROMString(MySocket, strPassword); TCPFlush(MySocket); break; case SM_GET_PASSWORD: case SM_GET_PASSWORD_BAD_LOGIN: // Make sure we can put the authenticated prompt if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strAuthenticated)) break; // See if the user pressed return w = TCPFind(MySocket, '\n', 0, FALSE); if(w == 0xFFFFu) { if(TCPGetRxFIFOFree(MySocket) == 0u) { TCPPutROMString(MySocket, (ROM BYTE*)"Too much data.\r\n"); TCPDisconnect(MySocket); } break; } // Search for the password -- case sensitive w2 = TCPFindROMArray(MySocket, (ROM BYTE*)PASSWORD, sizeof(PASSWORD)-1, 0, FALSE); if((w2 != 3) || !((sizeof(PASSWORD)-1 == w-3) || (sizeof(PASSWORD) == w-3)) || (TelnetState == SM_GET_PASSWORD_BAD_LOGIN)) { // Did not find the password TelnetState = SM_PRINT_LOGIN; TCPPutROMString(MySocket, strAccessDenied); TCPDisconnect(MySocket); break; } // Password verified, throw this line of data away TCPGetArray(MySocket, NULL, w + 1); // Print the authenticated prompt TCPPutROMString(MySocket, strAuthenticated); TelnetState = SM_AUTHENTICATED; // No break case SM_AUTHENTICATED: if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)strDisplay) + 4) break; TCPPutROMString(MySocket, strDisplay); TelnetState++; // All future characters will be bold TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[1m"); case SM_REFRESH_VALUES: if(TCPIsPutReady(MySocket) >= 60u) { //[10;1] //"Analog: 1023\r\n" //"Buttons: 3 2 1 0\r\n" //"LEDs: 7 6 5 4 3 2 1 0\r\n" // Position cursor at Line 10, Col 21 TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[10;21f"); // Put analog value with space padding on right side for 4 characters TCPPutROMArray(MySocket, (ROM BYTE*)" ", 4-strlen((char*)AN0String)); TCPPutString(MySocket, AN0String); // Put Buttons TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[11;18f"); TCPPut(MySocket, BUTTON3_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, BUTTON2_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, BUTTON1_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, BUTTON0_IO ? '1':'0'); // Put LEDs TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[12;10f"); TCPPut(MySocket, LED7_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED6_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED5_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED4_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED3_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED2_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED1_IO ? '1':'0'); TCPPut(MySocket, ' '); TCPPut(MySocket, LED0_IO ? '1':'0'); // Put cursor at beginning of next line TCPPutROMString(MySocket, (ROM BYTE*)"\x1b[13;1f"); // Send the data out immediately TCPFlush(MySocket); } if(TCPIsGetReady(MySocket)) { TCPGet(MySocket, &i); switch(i) { case '\r': case 'q': case 'Q': if(TCPIsPutReady(MySocket) >= strlenpgm((ROM char*)strGoodBye)) TCPPutROMString(MySocket, strGoodBye); TCPDisconnect(MySocket); TelnetState = SM_PRINT_LOGIN; break; } } break; } }