telnetd: Remove keep stdio feature

The Telnet service started via rtems_telnetd_start() had a keep stdio
feature.  This just created a task and executed the command function in
a loop.  For this kind of service we do not library support.  This can
be done by an application task on its own.  Remove this feature and
provide only the real Telnet server functionality.

Use syslog() for error and status messages.

Add test program for the Telnet server.

Close #3542.
This commit is contained in:
Sebastian Huber
2018-10-09 14:47:02 +02:00
parent 477bca2d61
commit 629faf9504
7 changed files with 220 additions and 78 deletions

View File

@@ -59,13 +59,14 @@ typedef struct {
/**
* @brief Task priority.
*
* If this parameter is equal to zero, then the priority of network task is
* used or 100 if this priority is less than two.
* Use 0 for the default value.
*/
rtems_task_priority priority;
/**
* @brief Task stack size.
*
* Use 0 for the default value.
*/
size_t stack_size;
@@ -77,12 +78,10 @@ typedef struct {
rtems_shell_login_check_t login_check;
/**
* @brief Keep standard IO of the caller.
* @brief This is an obsolete configuration option.
*
* Telnet takes over the standard input, output and error associated with
* task, if this parameter is set to @c true. In this case, it will @b not
* listen on any sockets. When this parameter is @c false, Telnet will
* create other tasks for the shell which listen on sockets.
* It must be set to false, otherwise rtems_telnetd_start() will do nothing
* and returns with a status of RTEMS_NOT_IMPLEMENTED.
*/
bool keep_stdio;
@@ -96,7 +95,15 @@ typedef struct {
} rtems_telnetd_config_table;
/**
* @brief Start the Telnet subsystem with the provided configuration.
* @brief Starts the Telnet server using the provided configuration.
*
* @retval RTEMS_SUCCESSFUL Successful operation.
* @retval RTEMS_INVALID_ADDRESS The command function in the configuration is
* @c NULL.
* @retval RTEMS_RESOURCE_IN_USE The Telnet server was already started.
* @retval RTEMS_NOT_IMPLEMENTED The keep stdio configuration option is true.
* @retval RTEMS_UNSATISFIED Not enough resources to start the Telnet server or
* task priority in configuration is invalid.
*/
rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table *config);

View File

@@ -234,67 +234,43 @@ rtems_task_telnetd(void *task_argument)
* was started from the console anyway ..
*/
do {
if (ctx->config.keep_stdio) {
bool start = true;
char device_name [32];
arg = grab_a_Connection(ctx, des_socket, &srv, peername,
sizeof(peername));
ttyname_r( 1, device_name, sizeof( device_name));
if (ctx->config.login_check != NULL) {
start = rtems_shell_login_prompt(
stdin,
stderr,
device_name,
ctx->config.login_check
);
}
if (start) {
ctx->config.command( device_name, ctx->config.arg);
} else {
syslog(
LOG_AUTHPRIV | LOG_WARNING,
"telnetd: to many wrong passwords entered from %s",
device_name
);
}
} else {
arg = grab_a_Connection(ctx, des_socket, &srv, peername,
sizeof(peername));
if (arg == NULL) {
/* if something went wrong, sleep for some time */
sleep(10);
continue;
}
if (arg == NULL) {
/* if something went wrong, sleep for some time */
sleep(10);
continue;
strncpy(arg->peername, peername, sizeof(arg->peername));
task_id = telnetd_spawn_task(
arg->pty.name,
ctx->config.priority,
ctx->config.stack_size,
spawned_shell,
arg
);
if (task_id == RTEMS_ID_NONE) {
FILE *dummy;
if ( telnetd_spawn_task != telnetd_dflt_spawn ) {
fprintf(stderr,"Telnetd: Unable to spawn child task\n");
}
strncpy(arg->peername, peername, sizeof(arg->peername));
/* hmm - the pty driver slot can only be
* released by opening and subsequently
* closing the PTY - this also closes
* the underlying socket. So we mock up
* a stream...
*/
task_id = telnetd_spawn_task(
arg->pty.name,
ctx->config.priority,
ctx->config.stack_size,
spawned_shell,
arg
);
if (task_id == RTEMS_ID_NONE) {
FILE *dummy;
if ( telnetd_spawn_task != telnetd_dflt_spawn ) {
fprintf(stderr,"Telnetd: Unable to spawn child task\n");
}
/* hmm - the pty driver slot can only be
* released by opening and subsequently
* closing the PTY - this also closes
* the underlying socket. So we mock up
* a stream...
*/
if ( !(dummy=fopen(arg->pty.name,"r+")) )
perror("Unable to dummy open the pty, losing a slot :-(");
release_a_Connection(ctx, arg->pty.name, peername, &dummy, 1);
free(arg);
sleep(2); /* don't accept connections too fast */
}
if ( !(dummy=fopen(arg->pty.name,"r+")) )
perror("Unable to dummy open the pty, losing a slot :-(");
release_a_Connection(ctx, arg->pty.name, peername, &dummy, 1);
free(arg);
sleep(2); /* don't accept connections too fast */
}
} while(1);
@@ -313,12 +289,12 @@ rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config)
rtems_id task_id;
if (config->command == NULL) {
fprintf(stderr, "telnetd setup with invalid command\n");
return RTEMS_IO_ERROR;
syslog(LOG_DAEMON | LOG_ERR, "telnetd: configuration with invalid command");
return RTEMS_INVALID_ADDRESS;
}
if (ctx->config.command != NULL) {
fprintf(stderr, "telnetd already started\n");
syslog(LOG_DAEMON | LOG_ERR, "telnetd: already started");
return RTEMS_RESOURCE_IN_USE;
}
@@ -353,19 +329,11 @@ rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config)
);
if (task_id == RTEMS_ID_NONE) {
ctx->config.command = NULL;
return RTEMS_IO_ERROR;
}
/* Print status */
if (!ctx->config.keep_stdio) {
fprintf(
stderr,
"telnetd started with stacksize = %u and priority = %d\n",
(unsigned) ctx->config.stack_size,
(unsigned) ctx->config.priority
);
syslog(LOG_DAEMON | LOG_ERR, "telnetd: cannot create server task");
return RTEMS_UNSATISFIED;
}
syslog(LOG_DAEMON | LOG_INFO, "telnetd: started successfully");
return RTEMS_SUCCESSFUL;
}

View File

@@ -1134,6 +1134,18 @@ tar03_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_tar03) \
$(support_includes)
endif
if NETTESTS
if TEST_telnetd01
lib_tests += telnetd01
lib_screens += telnetd01/telnetd01.scn
lib_docs += telnetd01/telnetd01.doc
telnetd01_SOURCES = telnetd01/init.c
telnetd01_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_telnetd01) \
$(support_includes) -I$(RTEMS_SOURCE_ROOT)/cpukit/libnetworking
telnetd01_LDADD = $(RTEMS_ROOT)cpukit/libtelnetd.a $(LDADD)
endif
endif
if TEST_termios
lib_tests += termios
termios_SOURCES = termios/init.c

View File

@@ -208,6 +208,7 @@ RTEMS_TEST_CHECK([syscall01])
RTEMS_TEST_CHECK([tar01])
RTEMS_TEST_CHECK([tar02])
RTEMS_TEST_CHECK([tar03])
RTEMS_TEST_CHECK([telnetd01])
RTEMS_TEST_CHECK([termios])
RTEMS_TEST_CHECK([termios01])
RTEMS_TEST_CHECK([termios02])

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2018 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <rtems.h>
#include <rtems/rtems_bsdnet.h>
#include <rtems/telnetd.h>
#include <tmacros.h>
const char rtems_test_name[] = "TELNETD 1";
struct rtems_bsdnet_config rtems_bsdnet_config;
static void command(char *device_name, void *arg)
{
}
static void test_command_null(void)
{
static const rtems_telnetd_config_table config = {
.command = NULL
};
rtems_status_code sc;
sc = rtems_telnetd_start(&config);
rtems_test_assert(sc == RTEMS_INVALID_ADDRESS);
}
static void test_cannot_start_server_task(void)
{
static const rtems_telnetd_config_table config = {
.command = command,
.priority = UINT32_MAX
};
rtems_status_code sc;
sc = rtems_telnetd_start(&config);
rtems_test_assert(sc == RTEMS_UNSATISFIED);
}
static void test_successful_start(void)
{
static const rtems_telnetd_config_table config = {
.command = command,
.stack_size = RTEMS_MINIMUM_STACK_SIZE
};
rtems_status_code sc;
sc = rtems_telnetd_start(&config);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
static void test_already_started(void)
{
static const rtems_telnetd_config_table config = {
.command = command
};
rtems_status_code sc;
sc = rtems_telnetd_start(&config);
rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE);
}
static rtems_task Init(rtems_task_argument argument)
{
int rv;
TEST_BEGIN();
rv = rtems_bsdnet_initialize_network();
rtems_test_assert(rv == 0);
test_command_null();
test_cannot_start_server_task();
test_successful_start();
test_already_started();
TEST_END();
rtems_test_exit(0);
}
#define CONFIGURE_INIT
#define CONFIGURE_MICROSECONDS_PER_TICK 10000
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 32
#define CONFIGURE_MAXIMUM_TASKS 7
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
#include <rtems/confdefs.h>

View File

@@ -0,0 +1,24 @@
#
# Copyright (c) 2018 embedded brains GmbH. All rights reserved.
#
# embedded brains GmbH
# Dornierstr. 4
# 82178 Puchheim
# Germany
# <rtems@embedded-brains.de>
#
# The license and distribution terms for this file may be
# found in the file LICENSE in this distribution or at
# http://www.rtems.org/license/LICENSE.
This file describes the directives and concepts tested by this test set.
test set name: telnetd01
directives:
- rtems_telnetd_start()
concepts:
+ Check if Telnet server works.

View File

@@ -0,0 +1,12 @@
*** BEGIN OF TEST TELNETD 1 ***
*** TEST VERSION: 5.0.0.dc32b6aa0807fb70f9b26bc0bc6e164ddb49bd3a
*** TEST STATE: EXPECTED-PASS
*** TEST BUILD: RTEMS_NETWORKING
*** TEST TOOLS: 7.3.0 20180125 (RTEMS 5, RSB 9670d7541e0621915e521fe76e7bb33de8cee661, Newlib d13c84eb07e35984bf7a974cd786a6cdac29e6b9)
syslog: telnetd: configuration with invalid command
Telnetd: spawning task failed (status: RTEMS_INVALID_PRIORITY)
syslog: telnetd: cannot create server task
syslog: telnetd: started successfully
syslog: telnetd: already started
*** END OF TEST TELNETD 1 ***