Network Component  Version 6.6
MDK-Professional Middleware for IP Networking
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Telnet Server

To enable a user to have access to a remote device, a command line interface needs to be in place on that device.

Command Line Interface

The Network Component's Telnet Server calls the telnet_server_process function when a command is received from the user. A command is any sequence of characters that is terminated by the CRLF sequence (the Enter key is pressed). The Telnet Server assembles this command and passes it as an argument to the telnet_server_process function.

The command line interface functions are located in the Telnet_Server_UIF.c template file. You must add this file to your project and customize it. You can add new commands or remove existing commands from the file. To add the template file to your project, simply right-click on the Source group, select Add New Item to Group, then click on User Code Template and scroll in the template files list until you find the Telnet Server template.

The following functions are implemented in this template file:

  • telnet_server_message - copies various system messages to the sending buffer for transmission to the Telnet Client. This function can also be used to support different languages.
  • telnet_server_message_poll - polls the upper-layer application for unsolicited messages.
  • telnet_server_process - called by the Telnet Server to process the commands entered by a remote user and to generate a response.

The following functions are included in the Network Component library rl_net.h:

Code Example Telnet_Server_UIF.c

#include <stdio.h>
#include "rl_net.h"
// Request message for Telnet server session.
uint32_t telnet_server_message (telnetServerMessage msg, char *buf, uint32_t len) {
uint32_t rlen = 0;
switch (msg) {
// Initial welcome message
/* Example
rlen = sprintf (buf, "\r\n"
"\r\n"
"Telnet Server ready\r\n");
*/
break;
// Prompt message
/* Example
rlen = sprintf (buf, "\r\n"
"Cmd> ");
*/
break;
// Login welcome message, if authentication is enabled
/* Example
rlen = sprintf (buf, "\r\n"
"Embedded Telnet Server\r\n"
"\r\n"
"Please login...");
*/
break;
// Username request login message
/* Example
rlen = sprintf (buf, "\r\n"
"Username: ");
*/
break;
// Password request login message
/* Example
rlen = sprintf (buf, "\r\n"
"Password: ");
*/
break;
// Incorrect login error message
/* Example
rlen = sprintf (buf, "\r\n"
"Login incorrect");
*/
break;
// Login timeout error message
/* Example
rlen = sprintf (buf, "\r\n"
"Login timeout\r\n");
*/
break;
// Unsolicited message (ie. from basic interpreter)
/* Example
rlen = sprintf (buf, "\r\n"
"Unsolicited message\r\n");
*/
break;
}
return (rlen);
}
// Poll the upper-layer user application for unsolicited messages.
bool telnet_server_message_poll (int32_t session) {
/* Example
extern bool msg_available;
if (session == 1 && msg_available == true) {
// Allow unsolicited messages on 1st session
msg_available = false;
return (true);
}
*/
return (false);
}
// Process a command and generate response.
uint32_t telnet_server_process (const char *cmd, char *buf, uint32_t buflen, uint32_t *pvar) {
uint32_t len = 0;
/* Example
extern int32_t AD_in (int32_t channel);
if (telnet_check_command (cmd, "ADIN0") == true) {
// Read analog input 0
len = sprintf (buf, "\r\n"
" ADIN0 = %d", AD_in(0));
return (len);
}
// ...
if (telnet_check_command (cmd, "BYE") == true) {
// Generate reply and disconnect
len = sprintf (buf, "\r\n"
"Disconnecting\r\n");
return (len | (1u<<30));
}
*/
return (len);
}

Access Filtering

For access filtering the function telnet_accept_client is used. It is part of the file Telnet_Server_Access.c. You need to adapt the function to the application's needs.

Code Example Telnet_Server_Access.c

#include "rl_net.h"
// Accept or deny connection from remote Telnet client.
// If this function is missing, all remote clients are accepted.
bool telnet_accept_client (const uint8_t *ip_addr, uint16_t port) {
/* Example
if (ip_addr[0] == 192 &&
ip_addr[1] == 168 &&
ip_addr[2] == 0 &&
ip_addr[3] == 1) {
// Accept connection.
return (true);
}
// Deny connection.
return (false);
*/
return (true);
}

Multi-user Authentication

The multi-user login allows you to create different profiles for different users or groups of users. The profiles define the access rights on the Telnet server. The users which are allowed to access the Telnet server are in the user database. The multi-user login allows you to selectively disable commands for unprivileged users.

If you want to use multi-user authentication, you must Enable User Authentication in the Net_Config_Telnet_Server.h configuration file.

The account defined in the Net_Config_Telnet_Server.h configuration file is a system administrator account, which has no restrictions. All other accounts are created in a separate Telnet_Server_Multiuser.c template file. You must add this file to your project and customize it. You can add new commands or remove existing commands from it. To add the template to your project, simply right-click on the Source group, select Add Net Item to Group, then click on User Code Template and scroll in the template files list until you find the Telnet Server Multi-user template (you will find a listing here).

The following function is included in this template:

The following function is included in the Network Component library rl_net.h:

  • telnet_get_user_id - retrieves the user identification number for the user, which is trying to access the file or folder.

Code Example Telnet_Server_Multiuser.c

#include <string.h>
#include "rl_net.h"
// Check if an user account exist in the user database.
uint8_t telnet_check_username (const char *username) {
/* Example
if (strcmp (username, "guest") == 0) {
// Username is correct
return (1);
}
*/
return (0);
}
// Check user account password in the user database.
bool telnet_check_password (uint8_t user_id, const char *password) {
/* Example
if (user_id == 1) {
if (strcmp (password, "guest") == 0) {
// Password is correct
return (true);
}
}
*/
return (false);
}
Note
  • If the Telnet_Server_Multiuser.c is not added to the project, but authentication is enabled, the Telnet server runs in single user authentication mode.
  • You can disable a system administrator account, if you set an empty string as the Authentication Username .

Example: Sending a Reply

The telnet_server_process function processes the Telnet command when it is received from a remote client. This function then generates a reply message and sends it back to the user. It is part of the Telnet_Server_UIF.c template file.

When the reply message is short, the whole message can be sent in a single TCP packet. However, when long reports are generated, multiple TCP packets must be sent to transfer the whole message. For example, when the log files are displayed this is often the case. Both single and multiple packets are supported by the Embedded Telnet Server.

Short Reply

In the following example, the Telnet command HELP is sent by the Telnet client:

cmd> HELP

This command is answered by the predefined help message tnet_help. This message is copied to the output buffer and sent to the remote Telnet client. The following code sends the reply message:

uint32_t telnet_server_process (const char *cmd, char *buf, uint32_t buflen, uint32_t *pvar) {
..
if (telnet_check_command (cmd, "HELP") == true || telnet_check_command (cmd, "?") == true) {
// 'HELP' command, display help text
len = sprintf (buf,tnet_help);
return (len);
}
..
}

Long Reply

A long reply message requires multiple calls to the function telnet_server_process. Each call to this function generates part of the reply message until the entire message is generated and sent. To distinguish between different calls to the function, the argument pvar is used. This argument is a pointer to a variable that is set to 0 on the first call and not altered on each subsequent call to this function. The function's return value, which specifies the number of bytes in the reply message, cannot exceed 1500. Hence the high bits of the function's return value is used to store the flags:

  • Repeat flag - bit 31 This flag tells the Telnet Server whether the function telnet_server_process must be called again or not (because the command processing is complete). The return value must be OR-ed with 1u<<31 to call the function again.
  • Disconnect flag - bit 30 This flag tells the Telnet Server to disconnect the Telnet connection. If this flag is set, the Telnet Server disconnects the current Telnet session. The return value must be OR-ed with 0x8000 to disconnect.

In the following example, the MEAS command is given by the user using the Telnet client.

cmd> MEAS

When a new Telnet command is received, the function telnet_server_process is called with the argument pvar set to 0. The command buffer cmd is checked to identify the command.

uint32_t telnet_server_process (const char *cmd, char *buf, uint32_t buflen, uint32_t *pvar) {
TCP_INFO *tsoc;
uint32_t val,ch,temp;
uint32_t len = 0;
switch (MYBUF(pvar)->id) {
case 0:
// First call to this function
break;
case 1:
// Command MEAS, repeated call
...
// Set request for another callback
return (len | 1u<<31);
...
}
// Simple command line parser
if (telnet_check_command (cmd, "MEAS") == true) {
// MEAS command given, monitor analog inputs
MYBUF(pvar)->id = 1;
if (len > 5) {
// We must be careful here, because data is overlaid.
sscanf (&cmd[5], "%d", &temp);
MYBUF(pvar)->nmax = temp;
}
len = sprintf (buf, meas_header);
if (MYBUF(pvar)->nmax) {
// Bit 31 is a repeat flag.
len |= 1u<<31;
}
return (len);
}

When a command is recognized, you can reuse the same command buffer to store local variables, which might be needed in repeated calls. During the repeated call to this function, the cmd buffer is locked and is not altered by the system. You can use it as temporary storage of variables for the repeated calls. Each Telnet session has its own buffer of 96 bytes, of which only 95 bytes can be used.

The above example uses 3 bytes of a storage variable pointed by pvar pointer for the following structure:

typedef struct {
uint8_t id;
uint8_t nmax;
uint8_t idx;
} MY_BUF;
#define MYBUF(p) ((MY_BUF *)p)

When the call to telnet_server_process is repeated for the same command, the value of a storage variable pointed to by argument pvar is not altered any more. You can use the value of pvar to process the command differently. The pvar buffer now holds the private structure MY_BUF, which is valid for the lifetime of processing the command. When the command processing is finished, this buffer is not used any more until the next command.

uint32_t telnet_server_process (const char *cmd, char *buf, uint32_t buflen, uint32_t *pvar) {
TCP_INFO *tsoc;
uint32_t val,ch,temp;
uint32_t len = 0;
switch (MYBUF(pvar)->id) {
case 0:
// First call to this function
break;
case 1:
// Command MEAS, repeated call
while (len < buflen-80) {
// Let's use as much of the buffer as possible
len += sprintf (buf+len, "\r\n%4d", MYBUF(pvar)->idx);
for (val = 0; val < 8; val++) {
len += sprintf (buf+len, "%7d", AD_in(val));
}
if (++MYBUF(pvar)->idx >= MYBUF(pvar)->nmax) {
// Requested number of measurements done
return (len);
}
}
// Set request for another callback
return (len | 1u<<31);
case 2:
// Repeated call, TCP status display
...
}

After giving a meas 4 command, the Telnet Client screen looks like this:

telnet_meas.png
Note
You can check the Telnet Server to see how it works.

Telnet Server Configuration

net_config_telnet_server_h.png
Telnet Server Configuration File

The Telnet server configuration file Net_Config_Telnet_Server.h contains the following settings:

  • Number of Telnet Sessions specifies the number of available Telnet sessions. The default value is one, and this enables only one concurrent client connection. You should increase this number if multiple Telnet clients must connect to the Telnet server at the same time.
  • Port Number specifies the listening TCP port number. The default Telnet server listening port is 23.
  • Idle Connection Timeout in seconds specifies the interval of user inactivity, after which the connection is automatically closed. During an idle session, no TCP frames are exchanged. A value of 0 disables a disconnection on timeout.
  • The Disable Echo switch enables or disables the Telnet Server echo mode. When disabled, the Telnet Server will not echo characters it receives.
  • The Enable User Authentication switch enables or disables authentication with a username and a password.
    • Authentication Realm is the string which is displayed in the browser's authentication dialogue if an authentication is required. This is a zero terminated string.
    • Authentication Username is the username for authentication.
    • Authentication Password is the default password, that must be stored in non-volatile memory. The user can change the password later.