How many protocol stacks are free above RTEMS ?
Jake Janovetz
janovetz at uiuc.edu
Wed Dec 13 15:22:26 UTC 2000
Sure... Here it is. It only does configuration of the
ethernet settings on my device, but at least it contains a
function (Telnetd_GetString) which strips out the IAC commands
that telnet specifies. Perhaps that could be useful. :-)
I wanted to rewrite some of the routines that RTEMS uses
for monitor purposes (CPU statistics, etc) so that they can
dump their information to an arbitrary (FILE *), but never
got around to it. Too many other things on the plate.
Jake
On Wed, Dec 13, 2000 at 10:39:24AM +0200, Antti P Miettinen wrote:
> "Jake Janovetz" <janovetz at uiuc.edu> writes:
> > TelnetD is something I've written, but since RTEMS doesn't really have
> > a default shell, it is fairly specific to the application.
>
> Would you like to share this? Being able to get rtems monitor prompt
> through telnet would probably be something that could fit into RTEMS
> distribution.
>
> --
> Antti P Miettinen
> Nokia Networks
-------------- next part --------------
/**************************************************************************
* telnetd.c *
**************************************************************************
* Description: *
* *
* Herein contains the telnet daemon. A TCP/IP-based system for *
* setting and querying certain configuration parameters and executing *
* commands. *
* *
* *
* The public routines contained in this file are: *
* *
* Telnetd_Start - Starts the telnet daemon. *
* *
* The private routines contained in this file are: *
* *
* Telnetd_Daemon - Background task that waits for telnet connections. *
* Telnetd_Session - Interactive session started for each telnet *
* session. *
* Telnetd_GetString - Handles getting strings from the connection *
* and processing telnet IAC commands. *
* *
**************************************************************************
* Change History: *
* 01/01/99 - Creation (JWJ) *
*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <rtems.h>
#include <rtems/rtems_bsdnet.h>
#include <rtems/error.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/telnet.h>
#include "init.h"
#include "monitor.h"
#include "telnetd.h"
static char help_text[] =
"\nCantante Control Commands:\n"
"--------------------------\n"
"ipaddr a.b.c.d - Set device IP address.\n" \
"netmask a.b.c.d - Set netmask.\n" \
"gwaddr a.b.c.d - Set gateway IP address.\n" \
"mp3addr a.b.c.d - Set MP3 server IP address.\n" \
"logaddr a.b.c.d - Set log host IP address (optional).\n" \
"deviceid x - Set device ID.\n" \
"location \"place\" - Set device location (use quotes).\n" \
"save - Save settings.\n" \
"exit - Close the telnet session.\n"
"reboot - Reboot.\n"
"\n" \
"'?' for help, '/' to list current settings.\n\n"
"\n";
/**************************************************************************
* Maximum receive buffer size for images.
*************************************************************************/
#define TELNETD_MAX_RECEIVESIZE (512*1024)
#define TELNETD_WELCOME_MSG "\n\nCantante telnetd v1.1\n" \
"Cantante MPEG Layer III Player\n" \
"Copyright (c) 1998-2000 Jake Janovetz\n\n"
struct session_info_t
{
FILE *sock_fp;
struct CantanteSettings current_settings;
struct CantanteSettings tentative_settings;
};
/**************************************************************************
* Function: Telnetd_GetString *
**************************************************************************
* Description: *
* *
* Here we retrieve a string from the given file descriptor. We also *
* handle IAC commands that come through the connection. *
* The command is supposed to 'look' and 'feel' like fgets. *
* *
* Similar to fgets, but with the following important differences: *
* + Eliminates telnet IAC commands from input stream. *
* + If the line exceeds n-1 characters, the remaining characters *
* are truncated. The returned string is still terminated with the \n.*
* *
* *
* Inputs: *
* *
* char *buf - Pointer to a buffer where the string will go. *
* int n - Maximum number of characters to receive into buf. *
* FILE *fp - File pointer describing the input stream. *
* *
* Output: *
* *
* char * - Pointer to the retrieved string. *
* *
**************************************************************************
* Change History: *
* 04/03/98 - Creation (JWJ) *
*************************************************************************/
static char *
Telnetd_GetString(char *buf, int n, FILE *fp)
{
char *s;
int c;
n--;
s = buf;
while (1)
{
c = fgetc(fp);
if (c == EOF)
return(NULL);
if (c == IAC)
{
c = fgetc(fp);
c = fgetc(fp);
continue;
}
*s++ = (char)c;
n--;
if (c == '\n')
{
*s = 0;
break;
}
if (n == 0)
{
s--;
n++;
}
}
return(buf);
}
static int
Telnetd_ScanIP(char *str, int *a, int *b, int *c, int *d)
{
if (sscanf(str, "%d.%d.%d.%d", a, b, c, d) != 4)
return(-1);
if ((*a < 0) || (*b < 0) || (*c < 0) || (*d < 0) ||
(*a > 255) || (*b > 255) || (*c > 255) || (*d > 255))
return(-1);
return(0);
}
/**************************************************************************
* Function: Telnetd_Session *
**************************************************************************
* Description: *
* *
* This task is started when the telnet daemon gets a service request *
* from a remote machine. This is the actual code for the session. *
* *
* *
* Inputs: *
* *
* rtems_task_argument arg - (not used) *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 04/03/98 - Creation (JWJ) *
*************************************************************************/
static void
Telnetd_Session(rtems_task_argument arg)
{
rtems_status_code sc;
struct session_info_t *info = NULL;
char cmd[256];
int a, b, c, d;
int done;
FILE *fp;
struct CantanteSettings current_settings;
struct CantanteSettings tentative_settings;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "telnetd: Could not retrieve notepad entry: %s",
strerror(errno));
sc = rtems_task_delete(RTEMS_SELF);
}
/***********************************************************************
* Retrieve current settings.
**********************************************************************/
Monitor_ReadCantanteSettings(¤t_settings);
tentative_settings = current_settings;
/***********************************************************************
* Print the telnet welcome message.
**********************************************************************/
fp = info->sock_fp;
fprintf(fp, TELNETD_WELCOME_MSG);
done = 0;
while (!done)
{
fprintf(fp, "cantante> ");
fflush(fp);
if (Telnetd_GetString(cmd, 80, fp) == NULL)
break;
if (cmd[0] == '?')
{
fprintf(fp, help_text);
fflush(fp);
}
else if (cmd[0] == '/')
{
Monitor_DisplaySettings(fp, current_settings,
tentative_settings);
fflush(fp);
}
else if (!strncmp(cmd, "ipaddr", 6))
{
if (Telnetd_ScanIP(&cmd[7], &a, &b, &c, &d) != 0)
fprintf(fp, " Error: Malformed IP address.\n");
else
{
tentative_settings.ipaddr[0] = a;
tentative_settings.ipaddr[1] = b;
tentative_settings.ipaddr[2] = c;
tentative_settings.ipaddr[3] = d;
}
}
else if (!strncmp(cmd, "netmask", 7))
{
if (Telnetd_ScanIP(&cmd[8], &a, &b, &c, &d) != 0)
fprintf(fp, " Error: Malformed netmask.\n");
else
{
tentative_settings.netmask[0] = a;
tentative_settings.netmask[1] = b;
tentative_settings.netmask[2] = c;
tentative_settings.netmask[3] = d;
}
}
else if (!strncmp(cmd, "gwaddr", 6))
{
if (Telnetd_ScanIP(&cmd[7], &a, &b, &c, &d) != 0)
fprintf(fp, " Error: Malformed gateway address.\n");
else
{
tentative_settings.gwaddr[0] = a;
tentative_settings.gwaddr[1] = b;
tentative_settings.gwaddr[2] = c;
tentative_settings.gwaddr[3] = d;
}
}
else if (!strncmp(cmd, "mp3addr", 7))
{
if (Telnetd_ScanIP(&cmd[8], &a, &b, &c, &d) != 0)
fprintf(fp, " Error: Malformed IP address.\n");
else
{
tentative_settings.mp3addr[0] = a;
tentative_settings.mp3addr[1] = b;
tentative_settings.mp3addr[2] = c;
tentative_settings.mp3addr[3] = d;
}
}
else if (!strncmp(cmd, "logaddr", 7))
{
if (Telnetd_ScanIP(&cmd[8], &a, &b, &c, &d) != 0)
fprintf(fp, " Error: Malformed IP address.\n");
else
{
tentative_settings.logaddr[0] = a;
tentative_settings.logaddr[1] = b;
tentative_settings.logaddr[2] = c;
tentative_settings.logaddr[3] = d;
}
}
else if (!strncmp(cmd, "deviceid", 8))
{
if (sscanf(&cmd[9], "%d", &a) != 1)
fprintf(fp, " Error: Must specify an integer device ID.\n");
else
tentative_settings.deviceID = a;
}
else if (!strncmp(cmd, "location", 8))
{
char str[30];
if (sscanf(&cmd[9], "\"%15[a-zA-Z0-9!@#$%%^&'*()/,._ -]\"", str) != 1)
fprintf(fp, " Error: Bad location string format.\n");
else
{
strncpy(tentative_settings.location, str, 16);
tentative_settings.location[16] = '\0';
}
}
else if (!strncmp(cmd, "save", 4))
{
fprintf(fp, "Saving ethernet settings...\n");
fflush(fp);
Monitor_WriteCantanteSettings(&tentative_settings);
Monitor_ReadCantanteSettings(¤t_settings);
}
else if (!strncmp(cmd, "exit", 4))
done = 1;
else if (!strncmp(cmd, "quit", 4))
done = 1;
else if (!strncmp(cmd, "reboot", 6))
{
fclose(fp);
rtems_task_wake_after(10);
rtems_panic(NULL);
}
else
fprintf(fp, "\n'?' for help, '/' to list current settings.\n");
}
fprintf(fp, "Goodbye.\n");
fflush(fp);
if (fclose(fp) < 0)
{
syslog(LOG_ERR, "telnetd: Could not close connection: %s",
strerror(errno));
}
free(info);
sc = rtems_task_delete(RTEMS_SELF);
syslog(LOG_ERR, "telnetd: Session task deletion failed: %s",
rtems_status_text(sc));
}
/**************************************************************************
* Function: Telnetd_Daemon *
**************************************************************************
* Description: *
* *
* *
* This task runs in the background. It waits for service requests *
* on a well-known port. When a request is received, it opens a new *
* telnet session. *
* *
* *
* Inputs: *
* *
* rtems_task_argument arg - not used. *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 04/03/98 - Creation (JWJ) *
*************************************************************************/
static void
Telnetd_Daemon(rtems_task_argument arg)
{
int s;
int s1;
int addrlen;
char sessionID;
rtems_task_priority priority;
rtems_status_code sc;
rtems_id tid;
struct sockaddr_in localAddr, remoteAddr;
struct session_info_t *info;
sessionID = 'a';
/***********************************************************************
* Create, bind, and listen on a selected port (normally the standard
* telnet port).
**********************************************************************/
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
syslog(LOG_ERR, "telnetd: Could not create socket: %s",
strerror(errno));
}
localAddr.sin_family = AF_INET;
localAddr.sin_port = TELNETD_PORT;
localAddr.sin_addr.s_addr = INADDR_ANY;
memset(localAddr.sin_zero, 0, sizeof(localAddr.sin_zero));
if (bind(s, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0)
{
syslog(LOG_ERR, "telnetd: Could not bind socket: %s", strerror(errno));
}
if (listen(s, 2) < 0)
{
syslog(LOG_ERR, "telnetd: Could not listen on socket: %s",
strerror(errno));
}
/***********************************************************************
* Enter an endless loop where we just accept connections from remote
* hosts. Each connection accepted causes a new telnet session to
* be created.
**********************************************************************/
while (1)
{
info = (struct session_info_t *)r_malloc(sizeof(struct session_info_t),
"Telnetd_Daemon");
addrlen = sizeof(remoteAddr);
s1 = accept(s, (struct sockaddr *)&remoteAddr, &addrlen);
if (s1 < 0)
{
syslog(LOG_ERR, "telnetd: Could not accept connection: %s",
strerror(errno));
}
rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
sc = rtems_task_create(rtems_build_name('T', 'N', 'S', sessionID),
priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE |
RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0),
RTEMS_FLOATING_POINT | RTEMS_LOCAL,
&tid);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "telnetd: Could not create telnet session: %s\n",
rtems_status_text(sc));
}
if (sessionID == 'z')
sessionID = 'a';
else
sessionID++;
if ((info->sock_fp = fdopen(s1, "r+")) == NULL)
{
close(s1);
syslog(LOG_ERR, "telnetd: Could not create file pointer: %s",
rtems_status_text(sc));
}
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "telnetd: Could not set telnet session notepad: %s\n",
rtems_status_text(sc));
}
sc = rtems_task_start(tid, Telnetd_Session, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "telnetd: Could not start telnet session: %s\n",
rtems_status_text(sc));
}
}
}
/**************************************************************************
* Function: Telnetd_Start *
**************************************************************************
* Description: *
* *
* Here, we start the Telnetd task which waits for telnet requests and *
* services them. This procedure returns to its caller once the *
* task is started. *
* *
* *
* Inputs: *
* *
* rtems_task_priority priority - Priority to assign to the daemons. *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 04/03/98 - Creation (JWJ) *
*************************************************************************/
void
Telnetd_Start(rtems_task_priority priority)
{
rtems_status_code sc;
rtems_id tid;
/***********************************************************************
* The daemon is a task that listens for connections to a certain
* port. That's all it does...
**********************************************************************/
sc = rtems_task_create(rtems_build_name('T', 'N', 'D', ' '),
priority, 4*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
&tid);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "telnetd: Could not create telnetd: %s\n",
rtems_status_text(sc));
}
sc = rtems_task_start(tid, Telnetd_Daemon, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "telnetd: Could not start telnetd: %s\n",
rtems_status_text(sc));
}
}
-------------- next part --------------
#ifndef __TELNETD_H__
#define __TELNETD_H__
#define TELNETD_PORT 23
void Telnetd_Start(rtems_task_priority priority);
#endif /* __TELNETD_H__ */
More information about the users
mailing list