/***************************************************************************** Function: SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen) Summary: This function accepts connection requests queued for a listening socket. Description: The accept function is used to accept connection requests queued for a listening socket. If a connection request is pending, accept removes the request from the queue, and a new socket is created for the connection. The original listening socket remains open and continues to queue new connection requests. The socket must be a SOCK_STREAM type socket. Precondition: listen function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. must be bound to a local name and in listening mode. addr - Optional pointer to a buffer that receives the address of the connecting entity. addrlen - Optional pointer to an integer that contains the length of the address addr Returns: If the accept function succeeds, it returns a non-negative integer that is a descriptor for the accepted socket. Otherwise, the value INVALID_SOCKET is returned. Remarks: None. ***************************************************************************/ SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen) { struct BSDSocket *pListenSock; SOCKET_INFO *remoteSockInfo; struct sockaddr_in *addrRemote; unsigned int sockCount; TCP_SOCKET hTCP; if( s >= BSD_SOCKET_COUNT ) return INVALID_SOCKET; pListenSock = &BSDSocketArray[s]; /* Get the pointer to listening server socket */ if ( pListenSock->bsdState != SKT_BSD_LISTEN ) return INVALID_SOCKET; if ( pListenSock->SocketType != SOCK_STREAM ) return INVALID_SOCKET; for(sockCount = 0; sockCount < BSD_SOCKET_COUNT; sockCount++) { if(BSDSocketArray[sockCount].bsdState != SKT_LISTEN) continue; if(BSDSocketArray[sockCount].localPort != pListenSock->localPort) continue; hTCP = BSDSocketArray[sockCount].SocketID; // We don't care about connections and disconnections before we can // process them, so clear the reset flag TCPWasReset(hTCP); if(TCPIsConnected(hTCP)) { remoteSockInfo = TCPGetRemoteInfo(hTCP); if(addr) { if(addrlen) { if((unsigned int)*addrlen < sizeof(struct sockaddr_in)) return INVALID_SOCKET; addrRemote = (struct sockaddr_in *)addr; addrRemote->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val; addrRemote->sin_port = remoteSockInfo->remotePort.Val; *addrlen = sizeof(struct sockaddr_in); } } BSDSocketArray[sockCount].remotePort = remoteSockInfo->remotePort.Val; BSDSocketArray[sockCount].remoteIP = remoteSockInfo->remote.IPAddr.Val; BSDSocketArray[sockCount].bsdState = SKT_EST; return sockCount; } } return INVALID_SOCKET; }
/***************************************************************************** Function: int listen( SOCKET s, int backlog ) Summary: The listen function sets the specified socket in a listen mode Description: This function sets the specified socket in a listen mode. Calling the listen function indicates that the application is ready to accept connection requests arriving at a socket of type SOCK_STREAM. The connection request is queued (if possible) until accepted with an accept function. The backlog parameter defines the maximum number of pending connections that may be queued. Precondition: bind() must have been called on the s socket first. Parameters: s - Socket identifier returned from a prior socket() call. backlog - Maximum number of connection requests that can be queued. Note that each backlog requires a TCP_PURPOSE_BERKELEY_SERVER type TCP socket to be allocated in the TCPSocketInitializer[] in TCPIPConfig.h. Also, ensure that BSD_SOCKET_COUNT (also in TCPIPConfig.h) is greater than the backlog by at least 1 (more if you have other BSD sockets in use). Returns: Returns 0 on success, else return SOCKET_ERROR. Remarks: None ***************************************************************************/ int listen( SOCKET s, int backlog ) { struct BSDSocket *ps; SOCKET clientSockID; unsigned int socketcount; unsigned char assigned; if( s >= BSD_SOCKET_COUNT ) return SOCKET_ERROR; ps = &BSDSocketArray[s]; if(ps->SocketType != SOCK_STREAM) return SOCKET_ERROR; if(ps->bsdState == SKT_BSD_LISTEN) backlog = ps->backlog; if((ps->bsdState != SKT_BOUND) && (ps->bsdState != SKT_BSD_LISTEN)) return SOCKET_ERROR; while(backlog--) { assigned = 0; for(socketcount = 0; socketcount < BSD_SOCKET_COUNT; socketcount++) { if(BSDSocketArray[socketcount].bsdState != SKT_CLOSED) continue; clientSockID = TCPOpen(0, TCP_OPEN_SERVER, ps->localPort, TCP_PURPOSE_BERKELEY_SERVER); if(clientSockID == INVALID_SOCKET) return SOCKET_ERROR; // Clear the first reset flag TCPWasReset(clientSockID); assigned = 1; ps->bsdState = SKT_BSD_LISTEN; ps->backlog = backlog; BSDSocketArray[socketcount].SocketID = clientSockID; BSDSocketArray[socketcount].bsdState = SKT_LISTEN; BSDSocketArray[socketcount].isServer = TRUE; BSDSocketArray[socketcount].localPort = ps->localPort; BSDSocketArray[socketcount].SocketType = SOCK_STREAM; break; } if(!assigned) return SOCKET_ERROR; } return 0; //Success }
/***************************************************************************** Function: static BOOL HandlePossibleTCPDisconnection(SOCKET s) Summary: Internal function that checks for asynchronous TCP connection state changes and resynchs the BSD socket descriptor state to match. Description: Internal function that checks for asynchronous TCP connection state changes and resynchs the BSD socket descriptor state to match. Precondition: None Parameters: s - TCP type socket descriptor returned from a previous call to socket. This socket must be in the SKT_LISTEN, SKT_IN_PROGRESS, SKT_EST, or SKT_DISCONNECTED states. Returns: TRUE - Socket is disconnected FALSE - Socket is ***************************************************************************/ static BOOL HandlePossibleTCPDisconnection(SOCKET s) { struct BSDSocket *socket; BYTE i; BOOL bSocketWasReset; socket = &BSDSocketArray[s]; // Nothing to do if disconnection has already been handled if(socket->bsdState == SKT_DISCONNECTED) return TRUE; // Find out if a disconnect has occurred bSocketWasReset = TCPWasReset(socket->SocketID); // For server sockets, if the parent listening socket is still open, // then return this socket to the queue for future backlog processing. if(socket->isServer) { for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++) { if(BSDSocketArray[i].bsdState != SKT_BSD_LISTEN) continue; if(BSDSocketArray[i].localPort == socket->localPort) { // Nothing to do if a disconnect has not occurred if(!bSocketWasReset) return FALSE; // Listener socket is still open, so just return to the // listening state so that the user must call accept() again to // reuse this BSD socket socket->bsdState = SKT_LISTEN; return TRUE; } } } // If we get down here and the socket was reset, then this socket // should be closed so that no more clients can connect to it. However, // we can't go to the BSD SKT_CLOSED state directly since the user still // has to call closesocket() with this s SOCKET descriptor first. if(bSocketWasReset) { TCPClose(socket->SocketID); socket->bsdState = SKT_DISCONNECTED; return TRUE; } return FALSE; }
/********************************************************************* * Function: void UART2TCPBridgeTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void UART2TCPBridgeTask(void) { static enum _BridgeState { SM_HOME = 0, SM_SOCKET_OBTAINED } BridgeState = SM_HOME; static TCP_SOCKET MySocket = INVALID_SOCKET; WORD wMaxPut, wMaxGet, w; BYTE *RXHeadPtrShadow, *RXTailPtrShadow; BYTE *TXHeadPtrShadow, *TXTailPtrShadow; switch(BridgeState) { case SM_HOME: #if defined(USE_REMOTE_TCP_SERVER) // Connect a socket to the remote TCP server MySocket = TCPOpen((DWORD)USE_REMOTE_TCP_SERVER, TCP_OPEN_ROM_HOST, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE); #else MySocket = TCPOpen(0, TCP_OPEN_SERVER, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE); #endif // Abort operation if no TCP socket of type TCP_PURPOSE_UART_2_TCP_BRIDGE is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; // Eat the first TCPWasReset() response so we don't // infinitely create and reset/destroy client mode sockets TCPWasReset(MySocket); // We have a socket now, advance to the next state BridgeState = SM_SOCKET_OBTAINED; break; case SM_SOCKET_OBTAINED: // Reset all buffers if the connection was lost if(TCPWasReset(MySocket)) { // Optionally discard anything in the UART FIFOs //RXHeadPtr = vUARTRXFIFO; //RXTailPtr = vUARTRXFIFO; //TXHeadPtr = vUARTTXFIFO; //TXTailPtr = vUARTTXFIFO; // If we were a client socket, close the socket and attempt to reconnect #if defined(USE_REMOTE_TCP_SERVER) TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; BridgeState = SM_HOME; break; #endif } // Don't do anything if nobody is connected to us if(!TCPIsConnected(MySocket)) break; // Make sure to clear UART errors so they don't block all future operations #if defined(__18CXX) if(RCSTAbits.OERR) { RCSTAbits.CREN = 0; RCSTAbits.CREN = 1; LED1_IO ^= 1; } if(RCSTAbits.FERR) { BYTE dummy = RCREG; LED2_IO ^= 1; } #else if(U2STAbits.OERR) U2STAbits.OERR = 0; #endif // Read FIFO pointers into a local shadow copy. Some pointers are volatile // (modified in the ISR), so we must do this safely by disabling interrupts RXTailPtrShadow = (BYTE*)RXTailPtr; TXHeadPtrShadow = (BYTE*)TXHeadPtr; #if defined(__18CXX) PIE1bits.RCIE = 0; PIE1bits.TXIE = 0; #else IEC1bits.U2RXIE = 0; IEC1bits.U2TXIE = 0; #endif RXHeadPtrShadow = (BYTE*)RXHeadPtr; TXTailPtrShadow = (BYTE*)TXTailPtr; #if defined(__18CXX) PIE1bits.RCIE = 1; if(TXHeadPtrShadow != TXTailPtrShadow) PIE1bits.TXIE = 1; #else IEC1bits.U2RXIE = 1; if(TXHeadPtrShadow != TXTailPtrShadow) IEC1bits.U2TXIE = 1; #endif // // Transmit pending data that has been placed into the UART RX FIFO (in the ISR) // wMaxPut = TCPIsPutReady(MySocket); // Get TCP TX FIFO space wMaxGet = RXHeadPtrShadow - RXTailPtrShadow; // Get UART RX FIFO byte count if(RXHeadPtrShadow < RXTailPtrShadow) wMaxGet += sizeof(vUARTRXFIFO); if(wMaxPut > wMaxGet) // Calculate the lesser of the two wMaxPut = wMaxGet; if(wMaxPut) // See if we can transfer anything { // Transfer the data over. Note that a two part put // may be needed if the data spans the vUARTRXFIFO // end to start address. w = vUARTRXFIFO + sizeof(vUARTRXFIFO) - RXTailPtrShadow; if(wMaxPut >= w) { TCPPutArray(MySocket, RXTailPtrShadow, w); RXTailPtrShadow = vUARTRXFIFO; wMaxPut -= w; } TCPPutArray(MySocket, RXTailPtrShadow, wMaxPut); RXTailPtrShadow += wMaxPut; // No flush. The stack will automatically flush and do // transmit coallescing to minimize the number of TCP // packets that get sent. If you explicitly call TCPFlush() // here, latency will go down, but so will max throughput // and bandwidth efficiency. } // // Transfer received TCP data into the UART TX FIFO for future transmission (in the ISR) // wMaxGet = TCPIsGetReady(MySocket); // Get TCP RX FIFO byte count wMaxPut = TXTailPtrShadow - TXHeadPtrShadow - 1;// Get UART TX FIFO free space if(TXHeadPtrShadow >= TXTailPtrShadow) wMaxPut += sizeof(vUARTTXFIFO); if(wMaxPut > wMaxGet) // Calculate the lesser of the two wMaxPut = wMaxGet; if(wMaxPut) // See if we can transfer anything { // Transfer the data over. Note that a two part put // may be needed if the data spans the vUARTTXFIFO // end to start address. w = vUARTTXFIFO + sizeof(vUARTTXFIFO) - TXHeadPtrShadow; if(wMaxPut >= w) { TCPGetArray(MySocket, TXHeadPtrShadow, w); TXHeadPtrShadow = vUARTTXFIFO; wMaxPut -= w; } TCPGetArray(MySocket, TXHeadPtrShadow, wMaxPut); TXHeadPtrShadow += wMaxPut; } // Write local shadowed FIFO pointers into the volatile FIFO pointers. #if defined(__18CXX) PIE1bits.RCIE = 0; PIE1bits.TXIE = 0; #else IEC1bits.U2RXIE = 0; IEC1bits.U2TXIE = 0; #endif RXTailPtr = (volatile BYTE*)RXTailPtrShadow; TXHeadPtr = (volatile BYTE*)TXHeadPtrShadow; #if defined(__18CXX) PIE1bits.RCIE = 1; if(TXHeadPtrShadow != TXTailPtrShadow) PIE1bits.TXIE = 1; #else IEC1bits.U2RXIE = 1; if(TXHeadPtrShadow != TXTailPtrShadow) IEC1bits.U2TXIE = 1; #endif break; } }
/********************************************************************* * void IO2TCPBridgeTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void IO2TCPBridgeTask(void) { static enum _BridgeState { SM_HOME = 0, SM_SOCKET_OBTAINED } BridgeState = SM_HOME; static TCP_SOCKET MySocket = INVALID_SOCKET; WORD wMaxPut, wMaxGet, w; BYTE *RXHeadPtrShadow, *RXTailPtrShadow; BYTE *TXHeadPtrShadow, *TXTailPtrShadow; switch(BridgeState) { case SM_HOME: #if defined(USE_REMOTE_TCP_SERVER) // Connect a socket to the remote TCP server MySocket = TCPOpen((DWORD)USE_REMOTE_TCP_SERVER, TCP_OPEN_ROM_HOST, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE); #else MySocket = TCPOpen(0, TCP_OPEN_SERVER, UART2TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE); #endif // Abort operation if no TCP socket of type TCP_PURPOSE_UART_2_TCP_BRIDGE is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; // Eat the first TCPWasReset() response so we don't // infinitely create and reset/destroy client mode sockets TCPWasReset(MySocket); // We have a socket now, advance to the next state BridgeState = SM_SOCKET_OBTAINED; break; case SM_SOCKET_OBTAINED: // Reset all buffers if the connection was lost if(TCPWasReset(MySocket)) { // Optionally discard anything in the UART FIFOs //RXHeadPtr = vUARTRXFIFO; //RXTailPtr = vUARTRXFIFO; //TXHeadPtr = vUARTTXFIFO; //TXTailPtr = vUARTTXFIFO; // If we were a client socket, close the socket and attempt to reconnect #if defined(USE_REMOTE_TCP_SERVER) TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; BridgeState = SM_HOME; break; #endif } // Don't do anything if nobody is connected to us if(!TCPIsConnected(MySocket)) break; if(TRUE == TxData) { //TCPPutArray(MySocket, keyinfo, 1); TCPPut(MySocket, keyinfo); TxData = FALSE; } // No flush. The stack will automatically flush and do // transmit coallescing to minimize the number of TCP // packets that get sent. If you explicitly call TCPFlush() // here, latency will go down, but so will max throughput // and bandwidth efficiency. break; } }
/***************************************************************************** Function: int connect( SOCKET s, struct sockaddr* name, int namelen ) Summary: This function connects to the peer communications end point. Description: The connect function assigns the address of the peer communications endpoint. For stream sockets, connection is established between the endpoints. For datagram sockets, an address filter is established between the endpoints until changed with another connect() function. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. name - pointer to the sockaddr structure containing the peer address and port number. namelen - length of the sockaddr structure. Returns: If the connect() function succeeds, it returns 0. Otherwise, the value SOCKET_ERROR is returned to indicate an error condition. For stream based socket, if the connection is not established yet, connect returns SOCKET_CNXN_IN_PROGRESS. Remarks: None. ***************************************************************************/ int connect( SOCKET s, struct sockaddr* name, int namelen ) { struct BSDSocket *socket; struct sockaddr_in *addr; DWORD remoteIP; WORD remotePort; WORD localPort; if( s >= BSD_SOCKET_COUNT ) return SOCKET_ERROR; socket = &BSDSocketArray[s]; if( socket->bsdState < SKT_CREATED ) return SOCKET_ERROR; if( (unsigned int)namelen < sizeof(struct sockaddr_in)) return SOCKET_ERROR; addr = (struct sockaddr_in *)name; remotePort = addr->sin_port; remoteIP = addr->sin_addr.S_un.S_addr; if( remoteIP == 0u || remotePort == 0u ) return SOCKET_ERROR; if( socket->SocketType == SOCK_STREAM ) { switch(socket->bsdState) { case SKT_EST: return 0; // already established case SKT_IN_PROGRESS: if(HandlePossibleTCPDisconnection(s)) return SOCKET_ERROR; if(!TCPIsConnected(socket->SocketID)) return SOCKET_CNXN_IN_PROGRESS; socket->bsdState = SKT_EST; return 0; //success case SKT_CREATED: case SKT_BOUND: socket->SocketID = TCPOpen(remoteIP, TCP_OPEN_IP_ADDRESS, remotePort, TCP_PURPOSE_BERKELEY_CLIENT); if(socket->SocketID == INVALID_SOCKET) return SOCKET_ERROR; // Clear the first reset flag TCPWasReset(socket->SocketID); socket->isServer = FALSE; socket->bsdState = SKT_IN_PROGRESS; return SOCKET_CNXN_IN_PROGRESS; default: return SOCKET_ERROR; } } else { // If not explicitly bound to a local port, implicitly do the binding if(socket->bsdState == SKT_CREATED) { localPort = gAutoPortNumber++; if(gAutoPortNumber > 5000u) // reset the port numbers gAutoPortNumber = 1024; //socket->SocketID = UDPOpen(localPort, NULL, remotePort); socket->SocketID = UDPOpenEx(0,UDP_OPEN_SERVER,localPort, remotePort); if(socket->SocketID == INVALID_UDP_SOCKET) return SOCKET_ERROR; socket->bsdState = SKT_BOUND; } if(socket->bsdState != SKT_BOUND) return SOCKET_ERROR; // UDP: remote port is used as a filter. Need to call connect when using // send/recv calls. No need to call 'connect' if using sendto/recvfrom // calls. socket->remotePort = remotePort; socket->remoteIP = remoteIP; return 0; //success } return SOCKET_ERROR; }
/********************************************************************* * 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; } }
void ModbusCmdTask(void) { static enum _BridgeState { SM_HOME = 0, SM_SOCKET_OBTAINED } BridgeState = SM_HOME; static TCP_SOCKET MySocket = INVALID_SOCKET; switch(BridgeState) { case SM_HOME: putrsUART((ROM char*)"\r\n in modbus sm home."); #if defined(DEBUG_TCP_CLIENT) //客户端 // Connect a socket to the remote TCP server MySocket = TCPOpen((DWORD)"192.168.1.36", TCP_OPEN_ROM_HOST, 502, TCP_PURPOSE_MODBUS_SERVER0); #else //服务器 MySocket = TCPOpen(0, TCP_OPEN_SERVER, 502, TCP_PURPOSE_MODBUS_SERVER0); #endif // Abort operation if no TCP socket of type TCP_PURPOSE_UART_2_TCP_BRIDGE is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; // Eat the first TCPWasReset() response so we don't // infinitely create and reset/destroy client mode sockets TCPWasReset(MySocket); // We have a socket now, advance to the next state BridgeState = SM_SOCKET_OBTAINED; break; case SM_SOCKET_OBTAINED: if(TCPWasReset(MySocket)) { // Optionally discard anything in the UART FIFOs //RXHeadPtr = vUARTRXFIFO; //RXTailPtr = vUARTRXFIFO; //TXHeadPtr = vUARTTXFIFO; //TXTailPtr = vUARTTXFIFO; // If we were a client socket, close the socket and attempt to reconnect #if defined(DEBUG_TCP_CLIENT) TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; BridgeState = SM_HOME; break; #endif } // Don't do anything if nobody is connected to us if(!TCPIsConnected(MySocket)) { break; } ModbusTcpRxHandle(MySocket); break; default: BridgeState = SM_HOME; break; } }
/********************************************************************* * 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; } }
/***************************************************************************** Function: int connect( SOCKET s, struct sockaddr* name, int namelen ) Summary: This function connects to the peer communications end point. Description: The connect function assigns the address of the peer communications endpoint. For stream sockets, connection is established between the endpoints. For datagram sockets, an address filter is established between the endpoints until changed with another connect() function. Precondition: socket function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. name - pointer to the sockaddr structure containing the peer address and port number. namelen - length of the sockaddr structure. Returns: If the connect() function succeeds, it returns 0. Otherwise, the value SOCKET_ERROR is returned to indicate an error condition (and errno set accordingly). For stream based socket, if the connection is not established yet, connect returns SOCKET_ERROR and errno = EINPROGRESS. Remarks: None. ***************************************************************************/ int connect( SOCKET s, struct sockaddr* name, int namelen ) { struct BSDSocket *socket; struct sockaddr_in *addr; uint32_t remoteIP; uint16_t remotePort; uint16_t localPort; IPV4_ADDR localAddr; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } socket = &BSDSocketArray[s]; if( socket->bsdState < SKT_CREATED ) { errno = EBADF; return SOCKET_ERROR; } if( (unsigned int)namelen < sizeof(struct sockaddr_in)) { errno = EFAULT; return SOCKET_ERROR; } addr = (struct sockaddr_in *)name; remotePort = addr->sin_port; remoteIP = addr->sin_addr.S_un.S_addr; if( remoteIP == 0u || remotePort == 0u ) { errno = EINVAL; return SOCKET_ERROR; } if( socket->SocketType == SOCK_STREAM ) { switch(socket->bsdState) { case SKT_EST: return 0; // already established case SKT_IN_PROGRESS: if(HandlePossibleTCPDisconnection(s)) { errno = ECONNREFUSED; return SOCKET_ERROR; } if(!TCPIsConnected(socket->SocketID)) { errno = EINPROGRESS; return SOCKET_ERROR; } socket->bsdState = SKT_EST; return 0; //success case SKT_CREATED: case SKT_BOUND: socket->SocketID = TCPOpenClient(IP_ADDRESS_TYPE_IPV4, remotePort, (IP_MULTI_ADDRESS*)&remoteIP); if(socket->SocketID == INVALID_SOCKET) { errno = ENOBUFS; return SOCKET_ERROR; } // Clear the first reset flag TCPWasReset(socket->SocketID); localAddr.Val = socket->localIP; TCPSocketSetNet(socket->SocketID, _TCPIPStackIpAddToNet(&localAddr, true)); socket->isServer = false; socket->bsdState = SKT_IN_PROGRESS; errno = EINPROGRESS; return SOCKET_ERROR; default: errno = ECONNRESET; return SOCKET_ERROR; } } else { // If not explicitly bound to a local port, implicitly do the binding if(socket->bsdState == SKT_CREATED) { IPV4_ADDR addrAny = {IP_ADDR_ANY}; localPort = gAutoPortNumber++; if(gAutoPortNumber > 5000u) // reset the port numbers gAutoPortNumber = 1024; socket->SocketID = UDPOpenServer(IP_ADDRESS_TYPE_IPV4, localPort, 0); if(socket->SocketID == INVALID_UDP_SOCKET) { errno = ENOBUFS; return SOCKET_ERROR; } UDPSocketSetNet(socket->SocketID, _TCPIPStackIpAddToNet(&addrAny, true)); socket->bsdState = SKT_BOUND; } if(socket->bsdState != SKT_BOUND) { errno = EINVAL; return SOCKET_ERROR; } // UDP: remote port is used as a filter. Need to call connect when using // send/recv calls. No need to call 'connect' if using sendto/recvfrom // calls. socket->remotePort = remotePort; socket->remoteIP = remoteIP; return 0; //success } errno = EINVAL; return SOCKET_ERROR; }
/********************************************************************* * Function: void CAN2TCPBridgeTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void CAN2TCPBridgeTask(void) { static enum _BridgeState { SM_HOME = 0, SM_SOCKET_OBTAINED } BridgeState = SM_HOME; static TCP_SOCKET MySocket = INVALID_SOCKET; WORD wMaxPut, wMaxGet, w; BYTE *RXHeadPtrShadow, *RXTailPtrShadow; BYTE *TXHeadPtrShadow, *TXTailPtrShadow; switch(BridgeState) { case SM_HOME: #if defined(USE_REMOTE_TCP_SERVER) // Connect a socket to the remote TCP server MySocket = TCPOpen((DWORD)USE_REMOTE_TCP_SERVER, TCP_OPEN_ROM_HOST, CAN2TCPBRIDGE_PORT, TCP_PURPOSE_CAN_2_TCP_BRIDGE); #else MySocket = TCPOpen(0, TCP_OPEN_SERVER, CAN2TCPBRIDGE_PORT, TCP_PURPOSE_CAN_2_TCP_BRIDGE); #endif // Abort operation if no TCP socket of type TCP_PURPOSE_CAN_2_TCP_BRIDGE is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; // Eat the first TCPWasReset() response so we don't // infinitely create and reset/destroy client mode sockets TCPWasReset(MySocket); // We have a socket now, advance to the next state BridgeState = SM_SOCKET_OBTAINED; break; case SM_SOCKET_OBTAINED: // Reset all buffers if the connection was lost if(TCPWasReset(MySocket)) { // Optionally discard anything in the CAN FIFOs RXHeadPtr = vCANRXFIFO; RXTailPtr = vCANRXFIFO; TXHeadPtr = vCANTXFIFO; TXTailPtr = vCANTXFIFO; // If we were a client socket, close the socket and attempt to reconnect #if defined(USE_REMOTE_TCP_SERVER) TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; BridgeState = SM_HOME; break; #endif } // Don't do anything if nobody is connected to us if(!TCPIsConnected(MySocket)) break; // Read FIFO pointers into a local shadow copy. Some pointers are volatile // (modified in the ISR), so we must do this safely by disabling interrupts RXTailPtrShadow = (BYTE*)RXTailPtr; TXHeadPtrShadow = (BYTE*)TXHeadPtr; CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, FALSE); CANEnableChannelEvent(CAN1, CAN_CHANNEL0, CAN_TX_CHANNEL_ANY_EVENT, FALSE); RXHeadPtrShadow = (BYTE*)RXHeadPtr; TXTailPtrShadow = (BYTE*)TXTailPtr; CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, TRUE); if(TXHeadPtrShadow != TXTailPtrShadow) CANEnableChannelEvent(CAN1, CAN_CHANNEL0, CAN_TX_CHANNEL_ANY_EVENT, TRUE); // // Transmit pending data that has been placed into the CAN RX FIFO (in the ISR) // wMaxPut = TCPIsPutReady(MySocket); // Get TCP TX FIFO space wMaxGet = RXHeadPtrShadow - RXTailPtrShadow; // Get CAN RX FIFO byte count if(RXHeadPtrShadow < RXTailPtrShadow) wMaxGet += sizeof(vCANRXFIFO); if(wMaxPut > wMaxGet) // Calculate the lesser of the two wMaxPut = wMaxGet; if(wMaxPut) // See if we can transfer anything { // Transfer the data over. Note that a two part put // may be needed if the data spans the vCANRXFIFO // end to start address. w = vCANRXFIFO + sizeof(vCANRXFIFO) - RXTailPtrShadow; if(wMaxPut >= w) { TCPPutArray(MySocket, RXTailPtrShadow, w); RXTailPtrShadow = vCANRXFIFO; wMaxPut -= w; } TCPPutArray(MySocket, RXTailPtrShadow, wMaxPut); RXTailPtrShadow += wMaxPut; // No flush. The stack will automatically flush and do // transmit coallescing to minimize the number of TCP // packets that get sent. If you explicitly call TCPFlush() // here, latency will go down, but so will max throughput // and bandwidth efficiency. } // // Transfer received TCP data into the CAN TX FIFO for future transmission (in the ISR) // wMaxGet = TCPIsGetReady(MySocket); // Get TCP RX FIFO byte count wMaxPut = TXTailPtrShadow - TXHeadPtrShadow - 1;// Get CAN TX FIFO free space if(TXHeadPtrShadow >= TXTailPtrShadow) wMaxPut += sizeof(vCANTXFIFO); if(wMaxPut > wMaxGet) // Calculate the lesser of the two wMaxPut = wMaxGet; if(wMaxPut) // See if we can transfer anything { // Transfer the data over. Note that a two part put // may be needed if the data spans the vCANTXFIFO // end to start address. w = vCANTXFIFO + sizeof(vCANTXFIFO) - TXHeadPtrShadow; if(wMaxPut >= w) { TCPGetArray(MySocket, TXHeadPtrShadow, w); TXHeadPtrShadow = vCANTXFIFO; wMaxPut -= w; } TCPGetArray(MySocket, TXHeadPtrShadow, wMaxPut); TXHeadPtrShadow += wMaxPut; } // Write local shadowed FIFO pointers into the volatile FIFO pointers. CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, FALSE); CANEnableChannelEvent(CAN1, CAN_CHANNEL0, CAN_TX_CHANNEL_ANY_EVENT, FALSE); RXTailPtr = (volatile BYTE*)RXTailPtrShadow; TXHeadPtr = (volatile BYTE*)TXHeadPtrShadow; CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, TRUE); if(TXHeadPtrShadow != TXTailPtrShadow) CANEnableChannelEvent(CAN1, CAN_CHANNEL0, CAN_TX_CHANNEL_ANY_EVENT, TRUE); break; } }
/***************************************************************************** Function: SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen) Summary: This function accepts connection requests queued for a listening socket. Description: The accept function is used to accept connection requests queued for a listening socket. If a connection request is pending, accept removes the request from the queue, and a new socket is created for the connection. The original listening socket remains open and continues to queue new connection requests. The socket must be a SOCK_STREAM type socket. Precondition: listen function should be called. Parameters: s - Socket descriptor returned from a previous call to socket. must be bound to a local name and in listening mode. addr - Optional pointer to a buffer that receives the address of the connecting entity. addrlen - Optional pointer to an integer that contains the length of the address addr Returns: If the accept function succeeds, it returns a non-negative integer that is a descriptor for the accepted socket. Otherwise, the value SOCKET_ERROR is returned. (and errno set accordingly). Remarks: None. ***************************************************************************/ SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen) { struct BSDSocket *pListenSock; TCP_SOCKET_INFO remoteSockInfo; struct sockaddr_in *addrRemote; unsigned int sockCount; TCP_SOCKET hTCP; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } pListenSock = &BSDSocketArray[s]; /* Get the pointer to listening server socket */ if ( pListenSock->bsdState != SKT_BSD_LISTEN ) { errno = EINVAL; return SOCKET_ERROR; } if ( pListenSock->SocketType != SOCK_STREAM ) { errno = EOPNOTSUPP; return SOCKET_ERROR; } for(sockCount = 0; sockCount < BSD_SOCKET_COUNT; sockCount++) { if(BSDSocketArray[sockCount].bsdState != SKT_LISTEN) continue; if(BSDSocketArray[sockCount].localPort != pListenSock->localPort) continue; hTCP = BSDSocketArray[sockCount].SocketID; // We don't care about connections and disconnections before we can // process them, so clear the reset flag TCPWasReset(hTCP); if(TCPIsConnected(hTCP)) { TCPGetSocketInfo(hTCP, &remoteSockInfo); if(addr) { if(addrlen) { if((unsigned int)*addrlen < sizeof(struct sockaddr_in)) { errno = EFAULT; return SOCKET_ERROR; } addrRemote = (struct sockaddr_in *)addr; addrRemote->sin_addr.S_un.S_addr = remoteSockInfo.remoteIPaddress.v4Add.Val; addrRemote->sin_port = remoteSockInfo.remotePort; *addrlen = sizeof(struct sockaddr_in); } } BSDSocketArray[sockCount].remotePort = remoteSockInfo.remotePort; BSDSocketArray[sockCount].remoteIP = remoteSockInfo.remoteIPaddress.v4Add.Val; BSDSocketArray[sockCount].bsdState = SKT_EST; return sockCount; } } errno = EMFILE; return SOCKET_ERROR; }
/***************************************************************************** Function: int listen( SOCKET s, int backlog ) Summary: The listen function sets the specified socket in a listen mode Description: This function sets the specified socket in a listen mode. Calling the listen function indicates that the application is ready to accept connection requests arriving at a socket of type SOCK_STREAM. The connection request is queued (if possible) until accepted with an accept function. The backlog parameter defines the maximum number of pending connections that may be queued. Precondition: bind() must have been called on the s socket first. Parameters: s - Socket identifier returned from a prior socket() call. backlog - Maximum number of connection requests that can be queued. Note that each backlog requires a TCP socket to be allocated. Also, ensure that BSD_SOCKET_COUNT (also in tcpip_config.h) is greater than the backlog by at least 1 (more if you have other BSD sockets in use). Returns: Returns 0 on success, else return SOCKET_ERROR. (and errno set accordingly). Remarks: None ***************************************************************************/ int listen( SOCKET s, int backlog ) { struct BSDSocket *ps; SOCKET clientSockID; unsigned int socketcount; unsigned char assigned; IPV4_ADDR lclAddr; if( s >= BSD_SOCKET_COUNT ) { errno = EBADF; return SOCKET_ERROR; } ps = &BSDSocketArray[s]; if(ps->SocketType != SOCK_STREAM) { errno = EOPNOTSUPP; return SOCKET_ERROR; } if(ps->bsdState == SKT_BSD_LISTEN) backlog = ps->backlog; if((ps->bsdState != SKT_BOUND) && (ps->bsdState != SKT_BSD_LISTEN)) { errno = EINVAL; return SOCKET_ERROR; } while(backlog--) { assigned = 0; for(socketcount = 0; socketcount < BSD_SOCKET_COUNT; socketcount++) { if(BSDSocketArray[socketcount].bsdState != SKT_CLOSED) continue; clientSockID = TCPOpenServer(IP_ADDRESS_TYPE_IPV4, ps->localPort, 0); if(clientSockID == INVALID_SOCKET) { errno = ENOBUFS; return SOCKET_ERROR; } lclAddr.Val = ps->localIP; TCPSocketSetNet(clientSockID, _TCPIPStackIpAddToNet(&lclAddr, true)); // Clear the first reset flag TCPWasReset(clientSockID); assigned = 1; ps->bsdState = SKT_BSD_LISTEN; ps->backlog = backlog; BSDSocketArray[socketcount].SocketID = clientSockID; BSDSocketArray[socketcount].bsdState = SKT_LISTEN; BSDSocketArray[socketcount].isServer = true; BSDSocketArray[socketcount].localPort = ps->localPort; BSDSocketArray[socketcount].SocketType = SOCK_STREAM; BSDSocketArray[socketcount].localIP = ps->localIP; break; } if(!assigned) { errno = EMFILE; return SOCKET_ERROR; } } return 0; //Success }
/********************************************************************* * Function: void UART2TCPBridgeTask(void) * * PreCondition: Stack is initialized() * * Input: None * * Output: None * * Side Effects: None * * Overview: None * * Note: None ********************************************************************/ void UART2TCPBridgeTask2(void) { static enum _BridgeState { SM_HOME = 0, SM_SOCKET_OBTAINED } BridgeState = SM_HOME; static TCP_SOCKET MySocket = INVALID_SOCKET; WORD wMaxPut, wMaxGet; //, w; //BYTE *RXHeadPtrShadow, *RXTailPtrShadow; //BYTE *TXHeadPtrShadow, *TXTailPtrShadow; unsigned char buffer[PACK_MAX_RX_SIZE]; DATA_RX_PACKET_T * prx; DATA_TX_PACKET_T * ptx; switch(BridgeState) { default: case SM_HOME: putrsUART((ROM char*)"\r\n IN UART2TCPBridgeTask() home"); #if defined(USE_REMOTE_TCP_SERVER) // Connect a socket to the remote TCP server MySocket = TCPOpen((DWORD)USE_REMOTE_TCP_SERVER, TCP_OPEN_ROM_HOST, UART1TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE); #else MySocket = TCPOpen(0, TCP_OPEN_SERVER, UART1TCPBRIDGE_PORT, TCP_PURPOSE_UART_2_TCP_BRIDGE); #endif // Abort operation if no TCP socket of type TCP_PURPOSE_UART_2_TCP_BRIDGE is available // If this ever happens, you need to go add one to TCPIPConfig.h if(MySocket == INVALID_SOCKET) break; // Eat the first TCPWasReset() response so we don't // infinitely create and reset/destroy client mode sockets TCPWasReset(MySocket); // We have a socket now, advance to the next state BridgeState = SM_SOCKET_OBTAINED; break; case SM_SOCKET_OBTAINED: //RELAY_OUT_1 = 0; // Reset all buffers if the connection was lost if(TCPWasReset(MySocket)) { // Optionally discard anything in the UART FIFOs //RXHeadPtr = vUARTRXFIFO; //RXTailPtr = vUARTRXFIFO; //TXHeadPtr = vUARTTXFIFO; //TXTailPtr = vUARTTXFIFO; // If we were a client socket, close the socket and attempt to reconnect #if defined(USE_REMOTE_TCP_SERVER) TCPDisconnect(MySocket); MySocket = INVALID_SOCKET; BridgeState = SM_HOME; break; #endif } // Don't do anything if nobody is connected to us if(!TCPIsConnected(MySocket)) { LED7_IO = 0; break; } LED7_IO = 1; // Make sure to clear UART errors so they don't block all future operations if(OERR2) //RCSTAbits.OERR) { //RCSTAbits.CREN = 0; CREN2 = 0; //RCSTAbits.CREN = 1; CREN2 = 1; LED1_IO ^= 1; } if(FERR2) //RCSTAbits.FERR) { BYTE dummy = RCREG2; //RCREG; LED2_IO ^= 1; } prx = GetFinishedPacket(); if(prx != NULL) { if(prx->finished) { if(prx->index > 0) { wMaxPut = TCPIsPutReady(MySocket); // Get TCP TX FIFO space wMaxPut = (prx->index > wMaxPut)?wMaxPut:prx->index; if(wMaxPut > 0) { TCPPutArray(MySocket, &(prx->buffer[0]), wMaxPut); prx->index = 0; prx->finished = 0; TCPFlush(MySocket); } } prx->index = 0; prx->finished = 0; //测试用 //if(THISINFO)putrsUART((ROM char *)"\r\UART Bridge look at it"); } } //PIE1bits.RCIE = 1; RC2IE = 1; wMaxGet = TCPIsGetReady(MySocket); // Get TCP RX FIFO byte count if(wMaxGet > 0) { DATA_TX_PACKET_T * ptx = find_next_empty_tx_buffer(); if(ptx != NULL) { wMaxGet = (wMaxGet > PACK_MAX_RX_SIZE)?PACK_MAX_RX_SIZE:wMaxGet; TCPGetArray(MySocket,(BYTE *)&buffer[0],wMaxGet); ptx = prase_in_buffer(buffer,wMaxGet); if(ptx != NULL) { if(ptx->index > 0) { //启动发送 //PIE1bits.TXIE = 1; TX2IE = 1; } } } } else { TCPDiscard(MySocket); } break; } }
/********************************************************************* * Function: static void HTTPProcess(void) * * PreCondition: HTTPInit() called and curHTTP loaded * * Input: None * * Output: None * * Side Effects: None * * Overview: Serves the current HTTP connection in curHTTP * * Note: None ********************************************************************/ static void HTTPProcess(void) { WORD lenA, lenB; BYTE c, i; BOOL isDone; BYTE *ext; BYTE buffer[HTTP_MAX_HEADER_LEN+1]; do { isDone = TRUE; // If a socket is disconnected at any time // forget about it and return to idle state. if(TCPWasReset(sktHTTP)) { smHTTP = SM_HTTP_IDLE; // Make sure any opened files are closed if(curHTTP.file != MPFS_INVALID_HANDLE) { MPFSClose(curHTTP.file); curHTTP.file = MPFS_INVALID_HANDLE; } if(curHTTP.offsets != MPFS_INVALID_HANDLE) { MPFSClose(curHTTP.offsets); curHTTP.offsets = MPFS_INVALID_HANDLE; } // Adjust the TCP FIFOs for optimal reception of // the next HTTP request from the browser TCPAdjustFIFOSize(sktHTTP, 1, 0, TCP_ADJUST_GIVE_REST_TO_RX | TCP_ADJUST_PRESERVE_RX); } switch(smHTTP) { case SM_HTTP_IDLE: // Check how much data is waiting lenA = TCPIsGetReady(sktHTTP); // If a connection has been made, then process the request if(lenA) {// Clear out state info and move to next state curHTTP.ptrData = curHTTP.data; smHTTP = SM_HTTP_PARSE_REQUEST; curHTTP.isAuthorized = 0xff; curHTTP.hasArgs = FALSE; curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND; curHTTP.callbackPos = 0xffffffff; curHTTP.byteCount = 0; } // In all cases, we break // For new connections, this waits for the buffer to fill break; case SM_HTTP_PARSE_REQUEST: // Verify the entire first line is in the FIFO if(TCPFind(sktHTTP, '\n', 0, FALSE) == 0xffff) {// First line isn't here yet if(TCPGetRxFIFOFree(sktHTTP) == 0) {// If the FIFO is full, we overflowed curHTTP.httpStatus = HTTP_OVERFLOW; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; } if(TickGet() > curHTTP.callbackID) {// A timeout has occurred TCPDisconnect(sktHTTP); smHTTP = SM_HTTP_DISCONNECT; isDone = FALSE; } break; } // Reset the watchdog timer curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND; // Determine the request method lenA = TCPFind(sktHTTP, ' ', 0, FALSE); if(lenA > 5) lenA = 5; TCPGetArray(sktHTTP, curHTTP.data, lenA+1); if ( memcmppgm2ram(curHTTP.data, (ROM void*)"GET", 3) == 0) curHTTP.httpStatus = HTTP_GET; #if defined(HTTP_USE_POST) else if ( memcmppgm2ram(curHTTP.data, (ROM void*)"POST", 4) == 0) curHTTP.httpStatus = HTTP_POST; #endif else {// Unrecognized method, so return not implemented curHTTP.httpStatus = HTTP_NOT_IMPLEMENTED; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } // Find end of filename lenA = TCPFind(sktHTTP, ' ', 0, FALSE); lenB = TCPFindEx(sktHTTP, '?', 0, lenA, FALSE); lenA = mMIN(lenA, lenB); // If the file name is too long, then reject the request if(lenA > HTTP_MAX_DATA_LEN - HTTP_DEFAULT_LEN - 1) { curHTTP.httpStatus = HTTP_OVERFLOW; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } // Read in the filename and decode lenB = TCPGetArray(sktHTTP, curHTTP.data, lenA); curHTTP.data[lenB] = '\0'; HTTPURLDecode(curHTTP.data); // Check if this is an MPFS Upload #if defined(HTTP_MPFS_UPLOAD) if(memcmppgm2ram(&curHTTP.data[1], HTTP_MPFS_UPLOAD, strlenpgm(HTTP_MPFS_UPLOAD)) == 0) {// Read remainder of line, and bypass all file opening, etc. #if defined(HTTP_USE_AUTHENTICATION) curHTTP.isAuthorized = HTTPAuthenticate(NULL, NULL, &curHTTP.data[1]); #endif if(curHTTP.httpStatus == HTTP_GET) curHTTP.httpStatus = HTTP_MPFS_FORM; else curHTTP.httpStatus = HTTP_MPFS_UP; smHTTP = SM_HTTP_PARSE_HEADERS; isDone = FALSE; break; } #endif // If the last character is a not a directory delimiter, then try to open the file // String starts at 2nd character, because the first is always a '/' if(curHTTP.data[lenB-1] != '/') curHTTP.file = MPFSOpen(&curHTTP.data[1]); // If the open fails, then add our default name and try again if(curHTTP.file == MPFS_INVALID_HANDLE) { // Add the directory delimiter if needed if(curHTTP.data[lenB-1] != '/') curHTTP.data[lenB++] = '/'; // Add our default file name // If this is a loopback, then it's an SSL connection if(TCPIsLoopback(sktHTTP)) { strcpypgm2ram((void*)&curHTTP.data[lenB], HTTPS_DEFAULT_FILE); lenB += strlenpgm(HTTPS_DEFAULT_FILE); } else { strcpypgm2ram((void*)&curHTTP.data[lenB], HTTP_DEFAULT_FILE); lenB += strlenpgm(HTTP_DEFAULT_FILE); } // Try to open again curHTTP.file = MPFSOpen(&curHTTP.data[1]); } // Find the extension in the filename for(ext = curHTTP.data + lenB-1; ext != curHTTP.data; ext--) if(*ext == '.') break; // Compare to known extensions to determine Content-Type ext++; for(curHTTP.fileType = HTTP_TXT; curHTTP.fileType < HTTP_UNKNOWN; curHTTP.fileType++) if(!stricmppgm2ram(ext, (ROM void*)httpFileExtensions[curHTTP.fileType])) break; // Perform first round authentication (pass file name only) #if defined(HTTP_USE_AUTHENTICATION) curHTTP.isAuthorized = HTTPAuthenticate(NULL, NULL, &curHTTP.data[1]); #endif // If the file was found, see if it has an index if(curHTTP.file != MPFS_INVALID_HANDLE && (MPFSGetFlags(curHTTP.file) & MPFS2_FLAG_HASINDEX) ) { curHTTP.data[lenB-1] = '#'; curHTTP.offsets = MPFSOpen(&curHTTP.data[1]); } // Read GET args, up to buffer size - 1 lenA = TCPFind(sktHTTP, ' ', 0, FALSE); if(lenA != 0) { curHTTP.hasArgs = TRUE; // Trash the '?' TCPGet(sktHTTP, &c); // Verify there's enough space lenA--; if(lenA >= HTTP_MAX_DATA_LEN - 2) { curHTTP.httpStatus = HTTP_OVERFLOW; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } // Read in the arguments and '&'-terminate in anticipation of cookies curHTTP.ptrData += TCPGetArray(sktHTTP, curHTTP.data, lenA); *(curHTTP.ptrData++) = '&'; } // Clear the rest of the line lenA = TCPFind(sktHTTP, '\n', 0, FALSE); TCPGetArray(sktHTTP, NULL, lenA + 1); // Move to parsing the headers smHTTP = SM_HTTP_PARSE_HEADERS; // No break, continue to parsing headers case SM_HTTP_PARSE_HEADERS: // Loop over all the headers while(1) { // Make sure entire line is in the FIFO lenA = TCPFind(sktHTTP, '\n', 0, FALSE); if(lenA == 0xffff) {// If not, make sure we can receive more data if(TCPGetRxFIFOFree(sktHTTP) == 0) {// Overflow curHTTP.httpStatus = HTTP_OVERFLOW; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; } if(TickGet() > curHTTP.callbackID) {// A timeout has occured TCPDisconnect(sktHTTP); smHTTP = SM_HTTP_DISCONNECT; isDone = FALSE; } break; } // Reset the watchdog timer curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND; // If a CRLF is immediate, then headers are done if(lenA == 1) {// Remove the CRLF and move to next state TCPGetArray(sktHTTP, NULL, 2); smHTTP = SM_HTTP_AUTHENTICATE; isDone = FALSE; break; } // Find the header name, and use isDone as a flag to indicate a match lenB = TCPFindEx(sktHTTP, ':', 0, lenA, FALSE) + 2; isDone = FALSE; // If name is too long or this line isn't a header, ignore it if(lenB > sizeof(buffer)) { TCPGetArray(sktHTTP, NULL, lenA+1); continue; } // Read in the header name TCPGetArray(sktHTTP, buffer, lenB); buffer[lenB-1] = '\0'; lenA -= lenB; // Compare header read to ones we're interested in for(i = 0; i < HTTP_NUM_HEADERS; i++) { if(strcmppgm2ram((char*)buffer, (ROM char *)HTTPRequestHeaders[i]) == 0) {// Parse the header and stop the loop HTTPHeaderParseLookup(i); isDone = TRUE; break; } } // Clear the rest of the line, and call the loop again if(isDone) {// We already know how much to remove unless a header was found lenA = TCPFind(sktHTTP, '\n', 0, FALSE); } TCPGetArray(sktHTTP, NULL, lenA+1); } break; case SM_HTTP_AUTHENTICATE: #if defined(HTTP_USE_AUTHENTICATION) // Check current authorization state if(curHTTP.isAuthorized < 0x80) {// 401 error curHTTP.httpStatus = HTTP_UNAUTHORIZED; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; #if defined(HTTP_NO_AUTH_WITHOUT_SSL) if(!TCPIsLoopback(sktHTTP)) curHTTP.httpStatus = HTTP_SSL_REQUIRED; #endif break; } #endif // Parse the args string *curHTTP.ptrData = '\0'; curHTTP.ptrData = HTTPURLDecode(curHTTP.data); // If this is an MPFS upload form request, bypass to headers #if defined(HTTP_MPFS_UPLOAD) if(curHTTP.httpStatus == HTTP_MPFS_FORM) { smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } #endif // Move on to GET args, unless there are none smHTTP = SM_HTTP_PROCESS_GET; if(!curHTTP.hasArgs) smHTTP = SM_HTTP_PROCESS_POST; isDone = FALSE; curHTTP.hasArgs = FALSE; break; case SM_HTTP_PROCESS_GET: // Run the application callback HTTPExecuteGet() if(HTTPExecuteGet() == HTTP_IO_WAITING) {// If waiting for asynchronous process, return to main app break; } // Move on to POST data smHTTP = SM_HTTP_PROCESS_POST; case SM_HTTP_PROCESS_POST: #if defined(HTTP_USE_POST) // See if we have any new data if(TCPIsGetReady(sktHTTP) == curHTTP.callbackPos) { if(TickGet() > curHTTP.callbackID) {// If a timeout has occured, disconnect TCPDisconnect(sktHTTP); smHTTP = SM_HTTP_DISCONNECT; isDone = FALSE; break; } } if(curHTTP.httpStatus == HTTP_POST #if defined(HTTP_MPFS_UPLOAD) || (curHTTP.httpStatus >= HTTP_MPFS_UP && curHTTP.httpStatus <= HTTP_MPFS_ERROR) #endif ) { // Run the application callback HTTPExecutePost() #if defined(HTTP_MPFS_UPLOAD) if(curHTTP.httpStatus >= HTTP_MPFS_UP && curHTTP.httpStatus <= HTTP_MPFS_ERROR) { c = HTTPMPFSUpload(); if(c == HTTP_IO_DONE) { smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } } else #endif c = HTTPExecutePost(); // If waiting for asynchronous process, return to main app if(c == HTTP_IO_WAITING) {// return to main app and make sure we don't get stuck by the watchdog curHTTP.callbackPos = TCPIsGetReady(sktHTTP) - 1; break; } else if(c == HTTP_IO_NEED_DATA) {// If waiting for more data curHTTP.callbackPos = TCPIsGetReady(sktHTTP); curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND; // If more is expected and space is available, return to main app if(curHTTP.byteCount > 0 && TCPGetRxFIFOFree(sktHTTP) != 0) break; else {// Handle cases where application ran out of data or buffer space curHTTP.httpStatus = HTTP_INTERNAL_SERVER_ERROR; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } } } #endif // We're done with POST smHTTP = SM_HTTP_PROCESS_REQUEST; // No break, continue to sending request case SM_HTTP_PROCESS_REQUEST: // Check for 404 if(curHTTP.file == MPFS_INVALID_HANDLE) { curHTTP.httpStatus = HTTP_NOT_FOUND; smHTTP = SM_HTTP_SERVE_HEADERS; isDone = FALSE; break; } // Set up the dynamic substitutions curHTTP.byteCount = 0; if(curHTTP.offsets == MPFS_INVALID_HANDLE) {// If no index file, then set next offset to huge curHTTP.nextCallback = 0xffffffff; } else {// Read in the next callback index MPFSGetLong(curHTTP.offsets, &(curHTTP.nextCallback)); } // Move to next state smHTTP = SM_HTTP_SERVE_HEADERS; case SM_HTTP_SERVE_HEADERS: // We're in write mode now: // Adjust the TCP FIFOs for optimal transmission of // the HTTP response to the browser TCPAdjustFIFOSize(sktHTTP, 1, 0, TCP_ADJUST_GIVE_REST_TO_TX); // Send headers TCPPutROMString(sktHTTP, (ROM BYTE*)HTTPResponseHeaders[curHTTP.httpStatus]); // If this is a redirect, print the rest of the Location: header if(curHTTP.httpStatus == HTTP_REDIRECT) { TCPPutString(sktHTTP, curHTTP.data); TCPPutROMString(sktHTTP, (ROM BYTE*)"\r\n\r\n304 Redirect: "); TCPPutString(sktHTTP, curHTTP.data); TCPPutROMString(sktHTTP, (ROM BYTE*)HTTP_CRLF); } // If not GET or POST, we're done if(curHTTP.httpStatus != HTTP_GET && curHTTP.httpStatus != HTTP_POST) {// Disconnect smHTTP = SM_HTTP_DISCONNECT; break; } // Output the content type, if known if(curHTTP.fileType != HTTP_UNKNOWN) { TCPPutROMString(sktHTTP, (ROM BYTE*)"Content-Type: "); TCPPutROMString(sktHTTP, (ROM BYTE*)httpContentTypes[curHTTP.fileType]); TCPPutROMString(sktHTTP, HTTP_CRLF); } // Output the gzip encoding header if needed if(MPFSGetFlags(curHTTP.file) & MPFS2_FLAG_ISZIPPED) { TCPPutROMString(sktHTTP, (ROM BYTE*)"Content-Encoding: gzip\r\n"); } // Output the cache-control TCPPutROMString(sktHTTP, (ROM BYTE*)"Cache-Control: "); if(curHTTP.httpStatus == HTTP_POST || curHTTP.nextCallback != 0xffffffff) {// This is a dynamic page or a POST request, so no cache TCPPutROMString(sktHTTP, (ROM BYTE*)"no-cache"); } else {// This is a static page, so save it for the specified amount of time TCPPutROMString(sktHTTP, (ROM BYTE*)"max-age="); TCPPutROMString(sktHTTP, (ROM BYTE*)HTTP_CACHE_LEN); } TCPPutROMString(sktHTTP, HTTP_CRLF); // Check if we should output cookies if(curHTTP.hasArgs) smHTTP = SM_HTTP_SERVE_COOKIES; else {// Terminate the headers TCPPutROMString(sktHTTP, HTTP_CRLF); smHTTP = SM_HTTP_SERVE_BODY; } // Move to next stage isDone = FALSE; break; case SM_HTTP_SERVE_COOKIES: #if defined(HTTP_USE_COOKIES) // If the TX FIFO runs out of space, the client will never get CRLFCRLF // Avoid writing huge cookies - keep it under a hundred bytes max // Write cookies one at a time as space permits for(curHTTP.ptrRead = curHTTP.data; curHTTP.hasArgs != 0; curHTTP.hasArgs--) { // Write the header TCPPutROMString(sktHTTP, (ROM BYTE*)"Set-Cookie: "); // Write the name, URL encoded, one character at a time while((c = *(curHTTP.ptrRead++))) { if(c == ' ') TCPPut(sktHTTP, '+'); else if(c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z') { TCPPut(sktHTTP, '%'); TCPPut(sktHTTP, btohexa_high(c)); TCPPut(sktHTTP, btohexa_low(c)); } else TCPPut(sktHTTP, c); } TCPPut(sktHTTP, '='); // Write the value, URL encoded, one character at a time while((c = *(curHTTP.ptrRead++))) { if(c == ' ') TCPPut(sktHTTP, '+'); else if(c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z') { TCPPut(sktHTTP, '%'); TCPPut(sktHTTP, btohexa_high(c)); TCPPut(sktHTTP, btohexa_low(c)); } else TCPPut(sktHTTP, c); } // Finish the line TCPPutROMString(sktHTTP, HTTP_CRLF); } #endif // We're done, move to next state TCPPutROMString(sktHTTP, HTTP_CRLF); smHTTP = SM_HTTP_SERVE_BODY; case SM_HTTP_SERVE_BODY: isDone = FALSE; // Try to send next packet if(HTTPSendFile()) {// If EOF, then we're done so close and disconnect MPFSClose(curHTTP.file); curHTTP.file = MPFS_INVALID_HANDLE; smHTTP = SM_HTTP_DISCONNECT; isDone = TRUE; } // If the TX FIFO is full, then return to main app loop if(TCPIsPutReady(sktHTTP) == 0) isDone = TRUE; break; case SM_HTTP_SEND_FROM_CALLBACK: isDone = TRUE; // Check that at least the minimum bytes are free if(TCPIsPutReady(sktHTTP) < HTTP_MIN_CALLBACK_FREE) break; // Fill TX FIFO from callback HTTPPrint(curHTTP.callbackID); if(curHTTP.callbackPos == 0) {// Callback finished its output, so move on isDone = FALSE; smHTTP = SM_HTTP_SERVE_BODY; }// Otherwise, callback needs more buffer space, so return and wait break; case SM_HTTP_DISCONNECT: // Loopbacks have no wait state, so all data must be retrieved first if(TCPIsLoopback(sktHTTP) && TCPGetTxFIFOFull(sktHTTP) != 0) break; // Make sure any opened files are closed if(curHTTP.file != MPFS_INVALID_HANDLE) { MPFSClose(curHTTP.file); curHTTP.file = MPFS_INVALID_HANDLE; } if(curHTTP.offsets != MPFS_INVALID_HANDLE) { MPFSClose(curHTTP.offsets); curHTTP.offsets = MPFS_INVALID_HANDLE; } TCPDisconnect(sktHTTP); smHTTP = SM_HTTP_IDLE; break; } } while(!isDone); }
void TelnetTask(void) { BYTE vTelnetSession; WORD w, w2; TCP_SOCKET MySocket; char outstr[60]; // 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; // Open an SSL listener if SSL server support is enabled #if defined(STACK_USE_SSL_SERVER) TCPAddSSLListener(MySocket, TELNETS_PORT); #endif TelnetState++; break; case SM_PRINT_LOGIN: #if defined(STACK_USE_SSL_SERVER) // Reject unsecured connections if TELNET_REJECT_UNSECURED is defined #if defined(TELNET_REJECT_UNSECURED) if(!TCPIsSSL(MySocket)) { if(TCPIsConnected(MySocket)) { TCPDisconnect(MySocket); TCPDisconnect(MySocket); break; } } #endif // Don't attempt to transmit anything if we are still handshaking. if(TCPSSLIsHandshaking(MySocket)) break; #endif sprintf(outstr,"%s%d%s",(char *)strTitle,AppConfig.SerialNumber,(char *)strTitle1); // Make certain the socket can be written to if(TCPIsPutReady(MySocket) < strlen(outstr)) break; // Place the application protocol data into the transmit buffer. TCPPutString(MySocket, (BYTE *)outstr); // 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 = TCPFindArray(MySocket, TELNET_USERNAME, strlen((char*)TELNET_USERNAME), 0, TRUE); if((w2 < 0) || !((w2 == ((w - strlen((char *)TELNET_USERNAME)) - 1)) || (w2 == (w - strlen((char *)TELNET_USERNAME))))) { // 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 = TCPFindArray(MySocket, TELNET_PASSWORD, strlen((char *)TELNET_PASSWORD), 0, FALSE); if((w2 != 3u) || !(((strlen((char *)TELNET_PASSWORD) == w-4)) || ((strlen((char *)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); TCPFlush(MySocket); TelnetState = SM_AUTHENTICATED; // No break case SM_AUTHENTICATED: break; } // Save session state back into the static array hTelnetSockets[vTelnetSession] = MySocket; vTelnetStates[vTelnetSession] = TelnetState; } }