Эх сурвалжийг харах

BT6706:
1) rewrite telnet server (turn on/off, change port functition)
2) translate string

balbekova 7 жил өмнө
parent
commit
7d71d19b8f

+ 349 - 155
modules/Telnet_Server/telnet_server.c

@@ -45,7 +45,12 @@ uint8_t id_change_pwd = 0;
 user_level_t telnet_code_auth = USER;
 
 static int32_t lClientFd;
+static int32_t lSocket;
 static int8_t *pcOutputString;
+static bool flagTelnetChange = false;
+static struct fd_set master_set, read_set, write_set;
+static int max_sd;
+static struct sockaddr_in sa;
 
 /**
   * @brief  Общая структура настроек
@@ -54,203 +59,392 @@ extern SETTINGS_t sSettings;
 
 /*-----------------------------------------------------------*/
 
+/* Stop server */
+static void stop_server(void) {
+    /* Clean up all of the sockets that are open */
+    for (int i = 0; i <= max_sd; ++i)
+    {
+       if (FD_ISSET(i, &master_set)) {
+          DBG printf("Close sock %d\n", i);
+          closesocket(i);
+          FD_CLR(i, &master_set);
+       }
+    }
+    DBG printf("Portgw stopped\n");
+}
+
+/* Start server */
+static bool start_server(uint16_t port)
+{
+    int res;
+
+    lSocket = socket(PF_INET, SOCK_STREAM, 0);
+
+    if (lSocket < 0) {
+      DBG printf("Socket create failed\r\n");
+      return false;
+    }
+
+    res = fcntl(lSocket, F_SETFL, O_NONBLOCK);
+    if (res < 0) {
+        DBG printf("fcntl() failed");
+        closesocket(lSocket);
+        return false;
+    }
+
+    memset(&sa, 0, sizeof(struct sockaddr_in));
+    sa.sin_family = AF_INET;
+    sa.sin_addr.s_addr = IPADDR_ANY;
+    sa.sin_port = htons(port);
+
+    if (bind(lSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
+    {
+        DBG printf("Bind to port %d failed\n", port);
+        closesocket(lSocket);
+        return false;
+    }
+
+    res = listen(lSocket, 20);
+    if (res < 0) {
+        DBG printf("Listen failed failed\r\n");
+        closesocket(lSocket);
+        return false;
+    }
+
+    FD_ZERO(&master_set);
+    max_sd = lSocket;
+    FD_SET(lSocket, &master_set);
+
+    DBG printf("Port %d opened\n", port);
+
+    return true;
+}
+
+
 void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 {
-int32_t lSocket, lBytes, lAddrLen = sizeof( struct sockaddr_in );
-struct sockaddr_in sLocalAddr;
-struct sockaddr_in client_addr;
-const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6706 command server - connection accepted.\r\nlogin:";
-static const int8_t * const pcEndOfCommandOutputString = ( int8_t * ) "\r\n[Press ENTER to execute the previous command again]\r\n>";
-int8_t cInChar, cInputIndex;
-static int8_t cInputString[ cmdMAX_INPUT_SIZE ] = { 0 }, cLastInputString[ cmdMAX_INPUT_SIZE ] = { 0 };
-portBASE_TYPE xReturned;
+	int32_t lBytes, lAddrLen = sizeof( struct sockaddr_in );
+	struct sockaddr_in sLocalAddr;
+	struct sockaddr_in client_addr;
+	const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6706 command server - connection accepted.\r\nlogin:";
+	static const int8_t * const pcEndOfCommandOutputString = ( int8_t * ) "\r\n[Нажмите клавишу ENTER для повторного выполнения предыдущей команды]\r\n>";
+	int8_t cInChar, cInputIndex;
+	static int8_t cInputString[ cmdMAX_INPUT_SIZE ] = { 0 }, cLastInputString[ cmdMAX_INPUT_SIZE ] = { 0 };
+	portBASE_TYPE xReturned;
+	int new_sd;
+    int desc_ready, rc;
+    struct timeval timeout;
+    bool close_conn;
+    uint16_t port;
+    bool enabled;
+    bool firstrun = true;
+
+    FD_ZERO(&master_set);
+
+	timeout.tv_sec = 5;
+	timeout.tv_usec = 0;
 
 	( void ) pvParameters;
+	pcOutputString = FreeRTOS_CLIGetOutputBuffer();
+    enabled = sSettings.sTelnet.TelnetEnable;
+    port = ( uint16_t ) sSettings.sTelnet.port;
+
+    while (1) {
+		/* Check if network settings was changed */
+		if ((sSettings.sTelnet.port != port) ||
+				(sSettings.sTelnet.TelnetEnable != enabled) ||
+				(firstrun))
+		{
 
-	lSocket = lwip_socket( AF_INET, SOCK_STREAM, 0 );
+			if (!firstrun || sSettings.sTelnet.port != port) {
+				/* Stop server */
+				stop_server();
+			}
 
-	if( lSocket >= 0 )
-	{
-		/* Obtain the address of the output buffer.  Note there is no mutual
-		exclusion on this buffer as it is assumed only one command console
-		interface will be used at any one time. */
-		pcOutputString = FreeRTOS_CLIGetOutputBuffer();
-
-		memset((char *)&sLocalAddr, 0, sizeof(sLocalAddr));
-		sLocalAddr.sin_family = AF_INET;
-		sLocalAddr.sin_len = sizeof(sLocalAddr);
-		sLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
-		sLocalAddr.sin_port = ntohs( ( ( uint16_t ) 23 ) );
-
-		if( lwip_bind( lSocket, ( struct sockaddr *) &sLocalAddr, sizeof( sLocalAddr ) ) < 0 )
-		{
-			lwip_close( lSocket );
-			vTaskDelete( NULL );
+			if (sSettings.sTelnet.TelnetEnable) {
+				/* (Re)start server */
+				if (!start_server(sSettings.sTelnet.port)) {
+					DBG printf("Server start error\n");
+					firstrun = true;
+					vTaskDelay(5000);
+					continue;
+				}
+			}
+			else {
+				/* Obtain the address of the output buffer.  Note there is no mutual
+				exclusion on this buffer as it is assumed only one command console
+				interface will be used at any one time. */
+				firstrun = true;
+				vTaskDelay(5000);
+				continue;
+			}
+			firstrun = false;
+
+			port = sSettings.sTelnet.port;
+			enabled = sSettings.sTelnet.TelnetEnable;
 		}
 
-		if( lwip_listen( lSocket, 20 ) != 0 )
-		{
-			lwip_close( lSocket );
-			vTaskDelete( NULL );
+		if (!enabled) {
+			firstrun = true;
+			vTaskDelay(5000);
+			continue;
 		}
 
-		/* Ensure the input string starts clear. */
-		cInputString[ 0 ] = 0;
-		cLastInputString[ 0 ] = 0;
 
-		for( ;; )
-		{
-			lClientFd = lwip_accept( lSocket, ( struct sockaddr * ) &client_addr, ( u32_t * ) &lAddrLen );
 
-			if( lClientFd > 0L )
-			{
-				lBytes = lwip_recv( lClientFd, cInputString, 27, 0 );
-				telnetState = TELNET_AUTH;
-				lwip_send( lClientFd, pcWelcomeMessage, strlen( ( const char * ) pcWelcomeMessage ), 0 );
+		memcpy(&read_set, &master_set, sizeof(master_set));
 
-				cInputIndex = 0;
-				memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+		DBG printf("Waiting on select()...\n");
+		rc = select(max_sd + 1, &read_set, NULL, NULL, &timeout);
 
-				do
-				{
-					lBytes = lwip_recv( lClientFd, &cInChar, sizeof( cInChar ), 0 );
+		DBG printf("  select() returned %d\n", rc);
 
-					if( lBytes > 0L )
-					{
-						if( cInChar == '\n' )
-						{
-							switch(telnetState){
-							case TELNET_AUTH:
-								if(FreeRTOS_CLIAuthProcess(cInputString, pcOutputString)){
-									lwip_send( lClientFd, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
-									cInputIndex = 0;
-									memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-								}
-								else{
-									/* Set lBytes to 0 to close the connection. */
-									lBytes = 0L;
-								}
-								break;
-							case TELNET_CMD:
-								/* The input string has been terminated.  Was the
-								input a quit command? */
-								if( strcmp( "quit", ( const char * ) cInputString ) == 0 )
-								{
-									/* Set lBytes to 0 to close the connection. */
-									lBytes = 0L;
-								}
-								else
-								{
-									/* The input string was not a quit command.
-									Pass the string to the command interpreter. */
+		if (rc < 0) {
+			DBG printf("  select() failed\n");
+		}
 
-									/* See if the command is empty, indicating that the last command is
-									to be executed again. */
-									if( cInputIndex == 0 )
-									{
-										strcpy( ( char * ) cInputString, ( char * ) cLastInputString );
-									}
+		if (rc == 0) {
+			DBG printf("  select() timed out.\n");
+		}
 
-									/* Transmit a line separator, just to make the
-									output easier to read. */
-									lwip_send( lClientFd, "\r\n", strlen( "\r\n" ), 0 );
+		/* One or more descriptors are readable.  Need to         \
+		 * determine which ones they are.                         */
+		desc_ready = rc;
+
+		for (int i=0; i <= max_sd  &&  desc_ready > 0; ++i) {
+			/*******************************************************/
+			/* Check to see if this descriptor is ready            */
+			/*******************************************************/
+			if (FD_ISSET(i, &read_set)) {
+				/* A descriptor was found that was readable - one  \
+				* less has to be looked for.  This is being done   \
+				* so that we can stop looking at the working set   \
+				* once we have found all of the descriptors that   \
+				* were ready.                                      */
+				desc_ready -= 1;
+
+				/* Check to see if this is the listening socket     */
+				if (i == lSocket) {
+					DBG printf("  Listening socket is readable\n");
+
+					/* Accept all incoming connections that are      */
+					/* queued up on the listening socket before we   */
+					/* loop back and call select again.              */
+					do {
+
+						/* Accept each incoming connection.  If       */
+						/* accept fails with EWOULDBLOCK, then we     */
+						/* have accepted all of them.  Any other      */
+						/* failure on accept will cause us to end the */
+						/* server.                                    */
+						new_sd = accept(lSocket, NULL, NULL);
+						if (new_sd < 0) {
+							if (errno != EWOULDBLOCK) {
+								DBG printf("  accept() failed\n");
+							}
+							break;
+						}
 
-									do
-									{
-										/* Ensure there is not a string lingering in
-										the output buffer. */
-										pcOutputString[ 0 ] = 0x00;
-										xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
-										lwip_send( lClientFd, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+						/* Add the new incoming connection to the     */
+						/* master read set                            */
+						printf("  New incoming connection - %d\n", new_sd);
+						FD_SET(new_sd, &master_set);
+						if (new_sd > max_sd) {
+							max_sd = new_sd;
+							recv( new_sd, cInputString, 27, 0 );
+							telnetState = TELNET_AUTH;
+							send( new_sd, pcWelcomeMessage, strlen( ( const char * ) pcWelcomeMessage ), 0 );
+
+							cInputIndex = 0;
+							memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+						}
+
+						/* Loop back up and accept another incoming   */
+						/* connection                                 */
+					} while (new_sd != -1);
+				}
 
-									} while( xReturned != pdFALSE );
+				/* This is not the listening socket, therefore an   */
+				/* existing connection must be readable             */
+				else {
+					DBG printf("  Descriptor %d is readable\n", i);
+					close_conn = false;
 
-									if( strcmp( "sensor info", ( const char * ) cInputString ) == 0 ){
-										strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
+					/* Receive data on this connection until the  */
+					/* recv fails with EWOULDBLOCK.  If any other */
+					/* failure occurs, we will close the          */
+					/* connection.                                */
+					if ((lBytes = recv(i, &cInChar, sizeof( cInChar ), 0 )) > 0) {
+
+						if( lBytes > 0L )
+						{
+							if( cInChar == '\n' )
+							{
+								switch(telnetState){
+								case TELNET_AUTH:
+									if(FreeRTOS_CLIAuthProcess(cInputString, pcOutputString)){
+										send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
 										cInputIndex = 0;
 										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-										xTimerStart(RepeatSensorInfoTimer, 0);
 									}
 									else{
-
-										/* All the strings generated by the input
-										command have been sent.  Clear the input
-										string ready to receive the next command.
-										Remember the command that was just processed
-										first in case it is to be processed again. */
-										strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
-										cInputIndex = 0;
-										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-										if(telnetState != TELNET_CHANGE_PWD)
-										lwip_send( lClientFd, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+										/* Set lBytes to 0 to close the connection. */
+										lBytes = 0L;
 									}
-								}
-								break;
-							case TELNET_CHANGE_PWD:
-								FreeRTOS_ChangePWDProcess(cInputString, pcOutputString);
-								lwip_send( lClientFd, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
-								cInputIndex = 0;
-								memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-								break;
+									break;
+								case TELNET_CMD:
+									/* The input string has been terminated.  Was the
+									input a quit command? */
+									if( strcmp( "quit", ( const char * ) cInputString ) == 0 )
+									{
+										/* Set lBytes to 0 to close the connection. */
+										lBytes = 0L;
+									}
+									else
+									{
+										/* The input string was not a quit command.
+										Pass the string to the command interpreter. */
+
+										/* See if the command is empty, indicating that the last command is
+										to be executed again. */
+										if( cInputIndex == 0 )
+										{
+											strcpy( ( char * ) cInputString, ( char * ) cLastInputString );
+										}
+
+										/* Transmit a line separator, just to make the
+										output easier to read. */
+										lwip_send( lClientFd, "\r\n", strlen( "\r\n" ), 0 );
+
+										do
+										{
+											/* Ensure there is not a string lingering in
+											the output buffer. */
+											pcOutputString[ 0 ] = 0x00;
+											xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
+											send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+
+										} while( xReturned != pdFALSE );
+
+										if( strcmp( "sensor info", ( const char * ) cInputString ) == 0 ){
+											strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
+											cInputIndex = 0;
+											memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+											lClientFd = i;
+											xTimerStart(RepeatSensorInfoTimer, 0);
+										}
+										else{
+
+											/* All the strings generated by the input
+											command have been sent.  Clear the input
+											string ready to receive the next command.
+											Remember the command that was just processed
+											first in case it is to be processed again. */
+											strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
+											cInputIndex = 0;
+											memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+											if(telnetState != TELNET_CHANGE_PWD)
+												send( i, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+										}
+									}
+									break;
+								case TELNET_CHANGE_PWD:
+									FreeRTOS_ChangePWDProcess(cInputString, pcOutputString);
+									send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+									cInputIndex = 0;
+									memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+									break;
 
-							}
+								}
 
-						}
-						else
-						{
-							if( cInChar == '\r' )
-							{
-								/* Ignore the character. */
 							}
-							else if( cInChar == '\b' )
+							else
 							{
-								/* Backspace was pressed.  Erase the last
-								character in the string - if any. */
-								if( cInputIndex > 0 )
+								if( cInChar == '\r' )
 								{
-									cInputIndex--;
-									cInputString[ cInputIndex ] = '\0';
+									/* Ignore the character. */
 								}
-							}
-							else
-							{
-								/* A character was entered.  Add it to the string
-								entered so far.  When a \n is entered the complete
-								string will be passed to the command interpreter. */
-								if( cInputIndex < cmdMAX_INPUT_SIZE )
+								else if( cInChar == '\b' )
 								{
-									cInputString[ cInputIndex ] = cInChar;
-									cInputIndex++;
+									/* Backspace was pressed.  Erase the last
+									character in the string - if any. */
+									if( cInputIndex > 0 )
+									{
+										cInputIndex--;
+										cInputString[ cInputIndex ] = '\0';
+									}
 								}
-								if( strcmp( "\377\364\377\375\006", ( const char * ) cInputString ) == 0 ){
-									xTimerStop(RepeatSensorInfoTimer, 0);
-									cInputIndex = 0;
-									memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-									cInputString[0] = 255;
-									cInputString[1] = 251;
-									cInputString[2] = 6;
-									cInputString[3] = 255;
-									cInputString[4] = 242;
-									//if(telnetState != TELNET_CHANGE_PWD)
-										//lwip_send( lClientFd, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
-									lwip_send( lClientFd, cInputString, strlen( ( const char * ) cInputString ), 0 );
-									memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-									if(telnetState != TELNET_CHANGE_PWD)
-										lwip_send( lClientFd, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+								else if( cInChar == '\t' ){
+									/*FreeRTOS_CLICompleteCMDCommand(cInputString, pcOutputString);
+									strcpy((char *)cInputString, (char *)pcOutputString);
+									send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );*/
+								}
+								else
+								{
+									/* A character was entered.  Add it to the string
+									entered so far.  When a \n is entered the complete
+									string will be passed to the command interpreter. */
+									if( cInputIndex < cmdMAX_INPUT_SIZE )
+									{
+										cInputString[ cInputIndex ] = cInChar;
+										cInputIndex++;
+									}
+									if( strcmp( "\377\364\377\375\006", ( const char * ) cInputString ) == 0 ){
+										xTimerStop(RepeatSensorInfoTimer, 0);
+										cInputIndex = 0;
+										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+										cInputString[0] = 255;
+										cInputString[1] = 251;
+										cInputString[2] = 6;
+										cInputString[3] = 255;
+										cInputString[4] = 242;
+										//if(telnetState != TELNET_CHANGE_PWD)
+											//lwip_send( lClientFd, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+										send( i, cInputString, strlen( ( const char * ) cInputString ), 0 );
+										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
+										if(telnetState != TELNET_CHANGE_PWD)
+											send( i, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+									}
 								}
 							}
 						}
 					}
 
-				} while( lBytes > 0L );
+					if (lBytes < 0) {
+						if (errno != EWOULDBLOCK){
+							DBG printf("  recv() failed\n");
+							close_conn = true;
+						}
+					}
 
-				 lwip_close( lClientFd );
+					/* Check to see if the connection has been    */
+					/* closed by the client                       */
+					if (lBytes == 0) {
+						DBG printf("  Connection closed\n");
+						close_conn = true;
+					}
+
+					/* If the close_conn flag was turned on, we need */
+					/* to clean up this active connection.  This     */
+					/* clean up process includes removing the        */
+					/* descriptor from the master set and            */
+					/* determining the new maximum descriptor value  */
+					/* based on the bits that are still turned on in */
+					/* the master set.                               */
+					if (close_conn) {
+						closesocket(i);
+						FD_CLR(i, &master_set);
+						if (i == max_sd) {
+						   while (FD_ISSET(max_sd, &master_set) == false) {
+							  max_sd -= 1;
+						   }
+						}
+					}
+				}
 			}
 		}
-	}
+    }
 
-	/* Will only get here if a listening socket could not be created. */
-	vTaskDelete( NULL );
 }
 
 void telnet_server_init(void) {

+ 4 - 0
modules/Telnet_Server/telnet_server.h

@@ -17,4 +17,8 @@ typedef enum{
 
 void telnet_server_init(void);
 
+void telnet_server_close(void);
+
+void telnet_server_port_change(void);
+
 #endif /* TELNET_SERVER_H_ */