Add new psock layer; telnet session is now wrapped in a character device
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4347 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
8a7c495ff1
commit
2223c0eac0
@ -164,3 +164,13 @@
|
|||||||
a USB serial console, then NSH needs to wait until the USB console is
|
a USB serial console, then NSH needs to wait until the USB console is
|
||||||
connected and available.
|
connected and available.
|
||||||
* apps/examples/composite: Add a test of the USB composite device.
|
* apps/examples/composite: Add a test of the USB composite device.
|
||||||
|
* apps/examples/telnetd: Move the tiny uIP shell example from
|
||||||
|
netutils/telnetd to examples/telnetd. Enhanced the telnetd daemon so that
|
||||||
|
it supports telnetd via a TTY device driver: A new TTY device driver is
|
||||||
|
created when each new telnet connection is created. The shell thread
|
||||||
|
is started with stdin, stdout, and stderror mapped to the TTY device.
|
||||||
|
* netutils/telnetd: The old uIP telnet demo is gone. In its place is a new
|
||||||
|
telnet infrastructure. The new telnet daemon creates sessions that are
|
||||||
|
"wrapped" as character devices and mapped to stdin, stdout, and stderr.
|
||||||
|
Now the telnet session can be inherited by spawned tasks.
|
||||||
|
* examples/telnetd: Add a test for the nte telnet daemon.
|
||||||
|
@ -40,8 +40,8 @@
|
|||||||
SUBDIRS = adc buttons can composite dhcpd ftpc hello helloxx hidkbd igmp \
|
SUBDIRS = adc buttons can composite dhcpd ftpc hello helloxx hidkbd igmp \
|
||||||
lcdrw mm mount nettest nsh null nx nxffs nxflat nxhello nximage \
|
lcdrw mm mount nettest nsh null nx nxffs nxflat nxhello nximage \
|
||||||
nxlines nxtext ostest pashello pipe poll pwm rgmp romfs sendmail \
|
nxlines nxtext ostest pashello pipe poll pwm rgmp romfs sendmail \
|
||||||
serloop thttpd tiff touchscreen udp uip usbserial usbstorage usbterm \
|
serloop telnetd thttpd tiff touchscreen udp uip usbserial \
|
||||||
wget wlan
|
usbstorage usbterm wget wlan
|
||||||
|
|
||||||
# Sub-directories that might need context setup. Directories may need
|
# Sub-directories that might need context setup. Directories may need
|
||||||
# context setup for a variety of reasons, but the most common is because
|
# context setup for a variety of reasons, but the most common is because
|
||||||
@ -56,7 +56,7 @@ SUBDIRS = adc buttons can composite dhcpd ftpc hello helloxx hidkbd igmp \
|
|||||||
CNTXTDIRS = pwm
|
CNTXTDIRS = pwm
|
||||||
|
|
||||||
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
|
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
|
||||||
CNTXTDIRS += adc can composite dhcpd nettest
|
CNTXTDIRS += adc can composite dhcpd nettest telnetd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y)
|
ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y)
|
||||||
|
@ -894,6 +894,28 @@ examples/serloop
|
|||||||
Use C buffered I/O (getchar/putchar) vs. raw console I/O
|
Use C buffered I/O (getchar/putchar) vs. raw console I/O
|
||||||
(read/read).
|
(read/read).
|
||||||
|
|
||||||
|
examples/telnetd
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This directory contains a functional port of the tiny uIP shell. In
|
||||||
|
the NuttX environment, the NuttShell (at apps/nshlib) supercedes this
|
||||||
|
tiny shell and also supports telnetd.
|
||||||
|
|
||||||
|
CONFIG_EXAMPLES_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
|
||||||
|
Default: SCHED_PRIORITY_DEFAULT
|
||||||
|
CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
|
||||||
|
Telnet daemon. Default: 2048
|
||||||
|
CONFIG_EXAMPLES_TELNETD_CLIENTPRIO- Priority of the Telnet client.
|
||||||
|
Default: SCHED_PRIORITY_DEFAULT
|
||||||
|
CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
|
||||||
|
Telnet client. Default: 2048
|
||||||
|
CONFIG_EXAMPLE_TELNETD_NOMAC - If the hardware has no MAC address of its
|
||||||
|
own, define this =y to provide a bogus address for testing.
|
||||||
|
CONFIG_EXAMPLE_TELNETD_IPADDR - The target IP address. Default 10.0.0.2
|
||||||
|
CONFIG_EXAMPLE_TELNETD_DRIPADDR - The default router address. Default
|
||||||
|
10.0.0.1
|
||||||
|
CONFIG_EXAMPLE_TELNETD_NETMASK - The network mask. Default: 255.255.255.0
|
||||||
|
|
||||||
examples/thttpd
|
examples/thttpd
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
105
examples/telnetd/Makefile
Normal file
105
examples/telnetd/Makefile
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
############################################################################
|
||||||
|
# apps/examples/telnetd/Makefile
|
||||||
|
#
|
||||||
|
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||||
|
# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in
|
||||||
|
# the documentation and/or other materials provided with the
|
||||||
|
# distribution.
|
||||||
|
# 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
# used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
-include $(TOPDIR)/.config
|
||||||
|
-include $(TOPDIR)/Make.defs
|
||||||
|
include $(APPDIR)/Make.defs
|
||||||
|
|
||||||
|
# Hello, World! Example
|
||||||
|
|
||||||
|
ASRCS =
|
||||||
|
CSRCS = shell.c
|
||||||
|
|
||||||
|
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||||
|
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||||
|
|
||||||
|
SRCS = $(ASRCS) $(CSRCS)
|
||||||
|
OBJS = $(AOBJS) $(COBJS)
|
||||||
|
|
||||||
|
ifeq ($(WINTOOL),y)
|
||||||
|
BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}"
|
||||||
|
else
|
||||||
|
BIN = "$(APPDIR)/libapps$(LIBEXT)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ROOTDEPPATH = --dep-path .
|
||||||
|
|
||||||
|
# Buttons built-in application info
|
||||||
|
|
||||||
|
APPNAME = buttons
|
||||||
|
PRIORITY = SCHED_PRIORITY_DEFAULT
|
||||||
|
STACKSIZE = 2048
|
||||||
|
|
||||||
|
# Common build
|
||||||
|
|
||||||
|
VPATH =
|
||||||
|
|
||||||
|
all: .built
|
||||||
|
.PHONY: context clean depend distclean
|
||||||
|
|
||||||
|
$(AOBJS): %$(OBJEXT): %.S
|
||||||
|
$(call ASSEMBLE, $<, $@)
|
||||||
|
|
||||||
|
$(COBJS): %$(OBJEXT): %.c
|
||||||
|
$(call COMPILE, $<, $@)
|
||||||
|
|
||||||
|
.built: $(OBJS)
|
||||||
|
@( for obj in $(OBJS) ; do \
|
||||||
|
$(call ARCHIVE, $(BIN), $${obj}); \
|
||||||
|
done ; )
|
||||||
|
@touch .built
|
||||||
|
|
||||||
|
.context:
|
||||||
|
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
|
||||||
|
$(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main)
|
||||||
|
@touch $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
context: .context
|
||||||
|
|
||||||
|
.depend: Makefile $(SRCS)
|
||||||
|
@$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
depend: .depend
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f *.o *~ .*.swp .built
|
||||||
|
$(call CLEAN)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
@rm -f Make.dep .depend
|
||||||
|
|
||||||
|
-include Make.dep
|
8
examples/telnetd/README.txt
Normal file
8
examples/telnetd/README.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
README.txt
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
This directory contains a functional port of the tiny uIP shell. In the
|
||||||
|
NuttX environment, the NuttShell (at apps/nshlib) supercedes this tiny
|
||||||
|
shell and also supports telnetd.
|
||||||
|
|
||||||
|
This example is retained here for reference purposes only.
|
251
examples/telnetd/shell.c
Normal file
251
examples/telnetd/shell.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* examples/telnetd/shell.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* This is a leverage of similar logic from uIP:
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
* Copyright (c) 2003, Adam Dunkels.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <apps/netutils/telnetd.h>
|
||||||
|
#include <apps/netutils/uiplib.h>
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
struct ptentry_s
|
||||||
|
{
|
||||||
|
FAR const char *commandstr;
|
||||||
|
void (*pfunc)(int argc, char **argv);
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void shell_help(int argc, char **argv);
|
||||||
|
static void shell_quit(int argc, char **argv);
|
||||||
|
static void shell_unknown(int argc, char **argv);
|
||||||
|
static void shell_parse(FAR char *line, int len);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static struct ptentry_s g_parsetab[] =
|
||||||
|
{
|
||||||
|
{"help", shell_help},
|
||||||
|
{"exit", shell_quit},
|
||||||
|
{"?", shell_help},
|
||||||
|
{NULL, shell_unknown}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: shell_help
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void shell_help(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("Available commands:");
|
||||||
|
printf(" help, ? - show help");
|
||||||
|
printf(" exit - exit shell");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: shell_help
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void shell_unknown(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argv[0])
|
||||||
|
{
|
||||||
|
printf("Unknown command: %s\n", argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: shell_quit
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void shell_quit(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("Bye!\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: shell_parse
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void shell_parse(FAR char *line, int len)
|
||||||
|
{
|
||||||
|
struct ptentry_s *entry;
|
||||||
|
FAR char *cmd;
|
||||||
|
FAR char *saveptr;
|
||||||
|
|
||||||
|
/* Get the command from the beginning the line */
|
||||||
|
|
||||||
|
cmd = strtok_r(line, " \t\n\r\f\v", &saveptr);
|
||||||
|
if (cmd)
|
||||||
|
{
|
||||||
|
/* Now find the matching command in the command table */
|
||||||
|
|
||||||
|
for (entry = g_parsetab; entry->commandstr != NULL; entry++)
|
||||||
|
{
|
||||||
|
if (strncmp(entry->commandstr, cmd, strlen(entry->commandstr)) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->pfunc(1, &cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: shell_session
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int shell_session(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char line[128];
|
||||||
|
|
||||||
|
printf("uIP command shell -- NuttX style");
|
||||||
|
printf("Type '?' and return for help");
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
printf(SHELL_PROMPT);
|
||||||
|
|
||||||
|
if (fgets(line, 128, stdin) == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_parse(line, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: shell_netinit
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void shell_netinit(void)
|
||||||
|
{
|
||||||
|
struct in_addr addr;
|
||||||
|
#ifdef CONFIG_EXAMPLE_TELNETD_NOMAC
|
||||||
|
uint8_t mac[IFHWADDRLEN];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Many embedded network interfaces must have a software assigned MAC */
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXAMPLE_TELNETD_NOMAC
|
||||||
|
mac[0] = 0x00;
|
||||||
|
mac[1] = 0xe0;
|
||||||
|
mac[2] = 0xb0;
|
||||||
|
mac[3] = 0x0b;
|
||||||
|
mac[4] = 0xba;
|
||||||
|
mac[5] = 0xbe;
|
||||||
|
uip_setmacaddr("eth0", mac);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set up our host address */
|
||||||
|
|
||||||
|
addr.s_addr = HTONL(CONFIG_EXAMPLE_TELNETD_IPADDR);
|
||||||
|
uip_sethostaddr("eth0", &addr);
|
||||||
|
|
||||||
|
/* Set up the default router address */
|
||||||
|
|
||||||
|
addr.s_addr = HTONL(CONFIG_EXAMPLE_TELNETD_DRIPADDR);
|
||||||
|
uip_setdraddr("eth0", &addr);
|
||||||
|
|
||||||
|
/* Setup the subnet mask */
|
||||||
|
|
||||||
|
addr.s_addr = HTONL(CONFIG_EXAMPLE_TELNETD_NETMASK);
|
||||||
|
uip_setnetmask("eth0", &addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int MAIN_NAME(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct telnetd_config_s config;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Configure the network */
|
||||||
|
|
||||||
|
printf(MAIN_STRING "Initializing the network\n");
|
||||||
|
shell_netinit();
|
||||||
|
|
||||||
|
/* Configure the telnet daemon */
|
||||||
|
|
||||||
|
config.d_port = HTONS(23);
|
||||||
|
config.d_priority = CONFIG_EXAMPLES_TELNETD_DAEMONPRIO;
|
||||||
|
config.d_stacksize = CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE;
|
||||||
|
config.t_priority = CONFIG_EXAMPLES_TELNETD_CLIENTPRIO;
|
||||||
|
config.t_stacksize = CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE;
|
||||||
|
config.t_entry = shell_session;
|
||||||
|
|
||||||
|
/* Start the telnet daemon */
|
||||||
|
|
||||||
|
printf(MAIN_STRING "Starting the Telnet daemon\n");
|
||||||
|
ret = telnetd_start(&config);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
printf("Failed to tart the Telnet daemon\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(MAIN_STRING "Exiting\n");
|
||||||
|
return 0;
|
||||||
|
}
|
103
examples/telnetd/shell.h
Normal file
103
examples/telnetd/shell.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* apps/examples/telnetd/shell.h
|
||||||
|
* Interface for the Contiki shell.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote
|
||||||
|
* products derived from this software without specific prior
|
||||||
|
* written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||||
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __APPS_EXAMPLES_TELNETD_SHELL_H
|
||||||
|
#define __APPS_EXAMPLES_TELNETD_SHELL_H
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
/* Configuration ************************************************************/
|
||||||
|
/* CONFIG_EXAMPLES_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
|
||||||
|
* Default: SCHED_PRIORITY_DEFAULT
|
||||||
|
* CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
|
||||||
|
* Telnet daemon. Default: 2048
|
||||||
|
* CONFIG_EXAMPLES_TELNETD_CLIENTPRIO- Priority of the Telnet client.
|
||||||
|
* Default: SCHED_PRIORITY_DEFAULT
|
||||||
|
* CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
|
||||||
|
* Telnet client. Default: 2048
|
||||||
|
* CONFIG_EXAMPLE_TELNETD_NOMAC - If the hardware has no MAC address of its
|
||||||
|
* own, define this =y to provide a bogus address for testing.
|
||||||
|
* CONFIG_EXAMPLE_TELNETD_IPADDR - The target IP address. Default 10.0.0.2
|
||||||
|
* CONFIG_EXAMPLE_TELNETD_DRIPADDR - The default router address. Default
|
||||||
|
* 10.0.0.1
|
||||||
|
* CONFIG_EXAMPLE_TELNETD_NETMASK - The network mask. Default: 255.255.255.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_EXAMPLES_TELNETD_DAEMONPRIO
|
||||||
|
# define CONFIG_EXAMPLES_TELNETD_DAEMONPRIO SCHED_PRIORITY_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE
|
||||||
|
# define CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE 2048
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_EXAMPLES_TELNETD_CLIENTPRIO
|
||||||
|
# define CONFIG_EXAMPLES_TELNETD_CLIENTPRIO SCHED_PRIORITY_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE
|
||||||
|
# define CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE 2048
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_EXAMPLE_TELNETD_IPADDR
|
||||||
|
# define CONFIG_EXAMPLE_TELNETD_IPADDR 0x0a000002
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_EXAMPLE_TELNETD_DRIPADDR
|
||||||
|
# define CONFIG_EXAMPLE_TELNETD_DRIPADDR 0x0a000002
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_EXAMPLE_TELNETD_NETMASK
|
||||||
|
# define CONFIG_EXAMPLE_TELNETD_NETMASK 0xffffff00
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Is this being built as an NSH built-in application? */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NSH_BUILTIN_APPS
|
||||||
|
# define MAIN_NAME shell_main
|
||||||
|
# define MAIN_STRING "shell_main: "
|
||||||
|
#else
|
||||||
|
# define MAIN_NAME user_start
|
||||||
|
# define MAIN_STRING "user_start: "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Other definitions ********************************************************/
|
||||||
|
|
||||||
|
#define SHELL_PROMPT "uIP 1.0> "
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __APPS_EXAMPLES_TELNETD_SHELL_H */
|
@ -1,14 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* include/apps/netutils/telnetd.h
|
* include/apps/netutils/telnetd.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007, 2011-2012 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
|
||||||
* This is a leverage of similar logic from uIP:
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
* Copyright (c) 2003, Adam Dunkels.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -17,35 +11,83 @@
|
|||||||
* 1. Redistributions of source code must retain the above copyright
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in
|
||||||
* documentation and/or other materials provided with the distribution.
|
* the documentation and/or other materials provided with the
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
* distribution.
|
||||||
* may be used to endorse or promote products derived from this software
|
* 3. Neither the name Gregory Nutt nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
* without specific prior written permission.
|
* without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
* SUCH DAMAGE.
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef __APPS_NETUTILS_TELNETD_H
|
#ifndef __APPS_INCLUDE_NETUTILS_TELNETD_H
|
||||||
#define __APPS_NETUTILS_TELNETD_H
|
#define __APPS_INCLUDE_NETUTILS_TELNETD_H
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Included Files
|
* Included Files
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Included Files
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
/* CONFIG_TELNETD_CONSOLE - Use the first telnet session as the default
|
||||||
|
* console.
|
||||||
|
* CONFIG_TELNETD_NPOLLWAITERS - If the poll method is enabled, then this
|
||||||
|
* value will defined the maximum number of threads that can be waiting
|
||||||
|
* for events. Default: 1
|
||||||
|
* CONFIG_TELNETD_DUMPBUFFER - dumping of all input/output buffers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_TELNETD_NPOLLWAITERS
|
||||||
|
# define CONFIG_TELNETD_NPOLLWAITERS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Configurable settings */
|
||||||
|
|
||||||
|
#ifndef CONFIG_TELNETD_IOBUFFER_SIZE
|
||||||
|
# define CONFIG_TELNETD_IOBUFFER_SIZE 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* An instance of the struct telnetd_config_s structure must be passed to
|
||||||
|
* telnetd_start in order to configure the new telnet daemon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct telnetd_config_s
|
||||||
|
{
|
||||||
|
/* These fields describe the telnet daemon */
|
||||||
|
|
||||||
|
int d_port; /* The port to listen on (in network byte order) */
|
||||||
|
int d_priority; /* The execution priority of the telnet daemon task */
|
||||||
|
int d_stacksize; /* The stack size needed by the telnet daemon task */
|
||||||
|
|
||||||
|
/* These fields describe the priority of each thread created by the telnet
|
||||||
|
* daemon.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int t_priority; /* The execution priority of the spawned task, */
|
||||||
|
int t_stacksize; /* The stack size needed by the spawned task */
|
||||||
|
main_t t_entry; /* The entrypoint of the task to spawn when a new
|
||||||
|
* connection is accepted. */
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Function Prototypes
|
* Public Function Prototypes
|
||||||
@ -58,13 +100,29 @@ extern "C" {
|
|||||||
#define EXTERN extern
|
#define EXTERN extern
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Start the telnet server -- does not return unless an error occurs */
|
/****************************************************************************
|
||||||
|
* Name: telnetd_start
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Start the telnet daemon.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* config A pointer to a configuration structure that characterizes the
|
||||||
|
* telnet daemon. This configuration structure may be defined
|
||||||
|
* on the caller's stack because it is not retained by the
|
||||||
|
* daemon.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* The process ID (pid) of the new telnet daemon is returned on
|
||||||
|
* success; A negated errno is returned if the daemon was not successfully
|
||||||
|
* started.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
EXTERN void telnetd_init(void);
|
EXTERN int telnetd_start(FAR struct telnetd_config_s *config);
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* __APPS_INCLUDE_NETUTILS_TELNETD_H */
|
||||||
#endif /* __APPS_NETUTILS_TELNETD_H */
|
|
||||||
|
@ -9,7 +9,6 @@ include:
|
|||||||
dhcpc - Dynamic Host Configuration Protocol (DHCP) client
|
dhcpc - Dynamic Host Configuration Protocol (DHCP) client
|
||||||
resolv - uIP DNS resolver
|
resolv - uIP DNS resolver
|
||||||
smtp - Simple Mail Transfer Protocol (SMTP) client
|
smtp - Simple Mail Transfer Protocol (SMTP) client
|
||||||
telnetd - TELNET server
|
|
||||||
webclient - HTTP web client
|
webclient - HTTP web client
|
||||||
webserver - HTTP web server
|
webserver - HTTP web server
|
||||||
|
|
||||||
@ -21,6 +20,12 @@ highly influenced by uIP) include:
|
|||||||
|
|
||||||
dhcpd - Dynamic Host Configuration Protocol (DHCP) server
|
dhcpd - Dynamic Host Configuration Protocol (DHCP) server
|
||||||
tftpc - TFTP client
|
tftpc - TFTP client
|
||||||
|
telnetd - TELNET server. This is the Telnet logic adapted from
|
||||||
|
uIP and generalized for use as the front end to any
|
||||||
|
shell. The telnet daemon creates sessions that are
|
||||||
|
"wrapped" as character devices and mapped to stdin,
|
||||||
|
stdout, and stderr. Now the telnet session can be
|
||||||
|
inherited by spawned tasks.
|
||||||
ftpc - FTP client
|
ftpc - FTP client
|
||||||
thttpd - This is a port of Jef Poskanzer's THTTPD HTPPD server.
|
thttpd - This is a port of Jef Poskanzer's THTTPD HTPPD server.
|
||||||
See http://acme.com/software/thttpd/.
|
See http://acme.com/software/thttpd/.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
############################################################################
|
############################################################################
|
||||||
# apps/netutils/telnetd/Makefile
|
# apps/netutils/telnetd/Makefile
|
||||||
#
|
#
|
||||||
# Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
|
||||||
# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# modification, are permitted provided that the following conditions
|
# modification, are permitted provided that the following conditions
|
||||||
@ -43,7 +43,7 @@ ASRCS =
|
|||||||
CSRCS =
|
CSRCS =
|
||||||
|
|
||||||
ifeq ($(CONFIG_NET_TCP),y)
|
ifeq ($(CONFIG_NET_TCP),y)
|
||||||
CSRCS += telnetd.c shell.c
|
CSRCS += telnetd_daemon.c telnetd_driver.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
This directory is here for historical reasons. Nothing contained in this
|
README.txt
|
||||||
directory is currently used by NuttX. This directly contains a functional
|
^^^^^^^^^^
|
||||||
port of the tiny uIP shell. In the NuttX environment, the NuttShell (at
|
|
||||||
apps/nshlib) supercedes this tiny shell and also supports telnetd.
|
|
||||||
|
|
||||||
This example is retained here for reference purposes only.
|
|
||||||
|
|
||||||
|
This directly contains a generic Telnet daemon.
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* netutils/telnetd/telnetd.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
||||||
*
|
|
||||||
* This is a leverage of similar logic from uIP:
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
* Copyright (c) 2003, Adam Dunkels.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Included Files
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "shell.h"
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Definitions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define SHELL_PROMPT "uIP 1.0> "
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Types
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
struct ptentry_s
|
|
||||||
{
|
|
||||||
char *commandstr;
|
|
||||||
void (* pfunc)(void *handle, char *str);
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Function Prototypes
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void parse(void *handle, register char *str, struct ptentry_s *t);
|
|
||||||
static void help(void *handle, char *str);
|
|
||||||
static void unknown(void *handle, char *str);
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Data
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static struct ptentry_s g_parsetab[] =
|
|
||||||
{
|
|
||||||
{"stats", help},
|
|
||||||
{"conn", help},
|
|
||||||
{"help", help},
|
|
||||||
{"exit", shell_quit},
|
|
||||||
{"?", help},
|
|
||||||
{NULL, unknown}
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void parse(void *handle, char *str, struct ptentry_s *t)
|
|
||||||
{
|
|
||||||
struct ptentry_s *p;
|
|
||||||
|
|
||||||
for (p = t; p->commandstr != NULL; ++p)
|
|
||||||
{
|
|
||||||
if (strncmp(p->commandstr, str, strlen(p->commandstr)) == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p->pfunc(handle, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void help(void *handle, char *str)
|
|
||||||
{
|
|
||||||
shell_output(handle, "Available commands:");
|
|
||||||
shell_output(handle, "stats - show network statistics");
|
|
||||||
shell_output(handle, "conn - show TCP connections");
|
|
||||||
shell_output(handle, "help, ? - show help");
|
|
||||||
shell_output(handle, "exit - exit shell");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unknown(void *handle, char *str)
|
|
||||||
{
|
|
||||||
if (strlen(str) > 0)
|
|
||||||
{
|
|
||||||
shell_output(handle, "Unknown command: ", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Public Functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
void shell_init(void *handle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void shell_start(void *handle)
|
|
||||||
{
|
|
||||||
shell_output(handle, "uIP command shell");
|
|
||||||
shell_output(handle, "Type '?' and return for help");
|
|
||||||
shell_prompt(handle, SHELL_PROMPT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shell_input(void *handle, char *cmd)
|
|
||||||
{
|
|
||||||
parse(handle, cmd, g_parsetab);
|
|
||||||
shell_prompt(handle, SHELL_PROMPT);
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* netutils/telnetd/shell.h
|
|
||||||
* Interface for the Contiki shell.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
||||||
*
|
|
||||||
* Based on uIP which also has a BSD style license:
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@dunkels.com>
|
|
||||||
* Copyright (c) 2003, Adam Dunkels.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote
|
|
||||||
* products derived from this software without specific prior
|
|
||||||
* written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
||||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
||||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/* Some of the functions declared in this file must be implemented as
|
|
||||||
* a shell back-end in the architecture specific files of a Contiki
|
|
||||||
* port.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SHELL_H__
|
|
||||||
#define __SHELL_H__
|
|
||||||
|
|
||||||
/* Initialize the shell.
|
|
||||||
*
|
|
||||||
* Called when the shell front-end process starts. This function may
|
|
||||||
* be used to start listening for signals.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void shell_init(void *handle);
|
|
||||||
|
|
||||||
/* Start the shell back-end.
|
|
||||||
*
|
|
||||||
* Called by the front-end when a new shell is started.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void shell_start(void *handle);
|
|
||||||
|
|
||||||
/* Process a shell command.
|
|
||||||
*
|
|
||||||
* This function will be called by the shell GUI / telnet server whan
|
|
||||||
* a command has been entered that should be processed by the shell
|
|
||||||
* back-end.
|
|
||||||
*
|
|
||||||
* command The command to be processed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void shell_input(void *handle, char *command);
|
|
||||||
|
|
||||||
/* Quit the shell. */
|
|
||||||
|
|
||||||
void shell_quit(void *handle, char *);
|
|
||||||
|
|
||||||
/* Print a string to the shell window.
|
|
||||||
*
|
|
||||||
* This function is implemented by the shell GUI / telnet server and
|
|
||||||
* can be called by the shell back-end to output a string in the
|
|
||||||
* shell window. The string is automatically appended with a linebreak.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void shell_output(void *handle, const char *fmt, ...);
|
|
||||||
|
|
||||||
/* Print a prompt to the shell window.
|
|
||||||
*
|
|
||||||
* This function can be used by the shell back-end to print out a
|
|
||||||
* prompt to the shell window.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void shell_prompt(void *handle, char *prompt);
|
|
||||||
|
|
||||||
#endif /* __SHELL_H__ */
|
|
@ -1,459 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* netutils/telnetd/telnetd.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
|
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
||||||
*
|
|
||||||
* This is a leverage of similar logic from uIP:
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
* Copyright (c) 2003, Adam Dunkels.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Included Files
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <nuttx/config.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
#include <apps/netutils/telnetd.h>
|
|
||||||
#include <apps/netutils/uiplib.h>
|
|
||||||
|
|
||||||
#include "shell.h"
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Definitions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define ISO_nl 0x0a
|
|
||||||
#define ISO_cr 0x0d
|
|
||||||
|
|
||||||
#define STATE_NORMAL 0
|
|
||||||
#define STATE_IAC 1
|
|
||||||
#define STATE_WILL 2
|
|
||||||
#define STATE_WONT 3
|
|
||||||
#define STATE_DO 4
|
|
||||||
#define STATE_DONT 5
|
|
||||||
#define STATE_CLOSE 6
|
|
||||||
|
|
||||||
#define TELNET_IAC 255
|
|
||||||
#define TELNET_WILL 251
|
|
||||||
#define TELNET_WONT 252
|
|
||||||
#define TELNET_DO 253
|
|
||||||
#define TELNET_DONT 254
|
|
||||||
|
|
||||||
/* Configurable settings */
|
|
||||||
|
|
||||||
#ifndef CONFIG_NETUTILS_IOBUFFER_SIZE
|
|
||||||
# define CONFIG_NETUTILS_IOBUFFER_SIZE 512
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_NETUTILS_CMD_SIZE
|
|
||||||
# define CONFIG_NETUTILS_CMD_SIZE 40
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* As threads are created to handle each request, a stack must be allocated
|
|
||||||
* for the thread. Use a default if the user provided no stacksize.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CONFIG_NETUTILS_TELNETDSTACKSIZE
|
|
||||||
# define CONFIG_NETUTILS_TELNETDSTACKSIZE 4096
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Enabled dumping of all input/output buffers */
|
|
||||||
|
|
||||||
#undef CONFIG_NETUTILS_TELNETD_DUMPBUFFER
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Types
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
struct telnetd_s
|
|
||||||
{
|
|
||||||
int tn_sockfd;
|
|
||||||
char tn_iobuffer[CONFIG_NETUTILS_IOBUFFER_SIZE];
|
|
||||||
char tn_cmd[CONFIG_NETUTILS_CMD_SIZE];
|
|
||||||
uint8_t tn_bufndx;
|
|
||||||
uint8_t tn_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: telnetd_dumpbuffer
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Dump a buffer of data (debug only)
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef CONFIG_NETUTILS_TELNETD_DUMPBUFFER
|
|
||||||
static inline void telnetd_dumpbuffer(FAR const char *msg, FAR const char *buffer, unsigned int nbytes)
|
|
||||||
{
|
|
||||||
/* CONFIG_DEBUG, CONFIG_DEBUG_VERBOSE, and CONFIG_DEBUG_NET have to be
|
|
||||||
* defined or the following does nothing.
|
|
||||||
*/
|
|
||||||
|
|
||||||
nvdbgdumpbuffer(msg, (FAR const uint8_t*)buffer, nbytes);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# define telnetd_dumpbuffer(msg,buffer,nbytes)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: telnetd_putchar
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Add another parsed character to the TELNET command string
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void telnetd_putchar(struct telnetd_s *pstate, uint8_t ch)
|
|
||||||
{
|
|
||||||
/* Ignore carriage returns */
|
|
||||||
|
|
||||||
if (ch == ISO_cr)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add all other characters to the cmd buffer */
|
|
||||||
|
|
||||||
pstate->tn_cmd[pstate->tn_bufndx] = ch;
|
|
||||||
|
|
||||||
/* If a newline was added or if the buffer is full, then process it now */
|
|
||||||
|
|
||||||
if (ch == ISO_nl || pstate->tn_bufndx == (CONFIG_NETUTILS_CMD_SIZE - 1))
|
|
||||||
{
|
|
||||||
if (pstate->tn_bufndx > 0)
|
|
||||||
{
|
|
||||||
pstate->tn_cmd[pstate->tn_bufndx] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
telnetd_dumpbuffer("TELNET CMD", pstate->tn_cmd, strlen(pstate->tn_cmd));
|
|
||||||
shell_input(pstate, pstate->tn_cmd);
|
|
||||||
pstate->tn_bufndx = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pstate->tn_bufndx++;
|
|
||||||
vdbg("Add '%c', bufndx=%d\n", ch, pstate->tn_bufndx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: telnetd_sendopt
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void telnetd_sendopt(struct telnetd_s *pstate, uint8_t option, uint8_t value)
|
|
||||||
{
|
|
||||||
uint8_t optbuf[4];
|
|
||||||
optbuf[0] = TELNET_IAC;
|
|
||||||
optbuf[1] = option;
|
|
||||||
optbuf[2] = value;
|
|
||||||
optbuf[3] = 0;
|
|
||||||
|
|
||||||
telnetd_dumpbuffer("Send optbuf", optbuf, 4);
|
|
||||||
if (send(pstate->tn_sockfd, optbuf, 4, 0) < 0)
|
|
||||||
{
|
|
||||||
dbg("[%d] Failed to send TELNET_IAC\n", pstate->tn_sockfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: telnetd_receive
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Process a received TELENET buffer
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int telnetd_receive(struct telnetd_s *pstate, size_t len)
|
|
||||||
{
|
|
||||||
char *ptr = pstate->tn_iobuffer;
|
|
||||||
uint8_t ch;
|
|
||||||
|
|
||||||
while (len > 0)
|
|
||||||
{
|
|
||||||
ch = *ptr++;
|
|
||||||
len--;
|
|
||||||
|
|
||||||
vdbg("ch=%02x state=%d\n", ch, pstate->tn_state);
|
|
||||||
switch (pstate->tn_state)
|
|
||||||
{
|
|
||||||
case STATE_IAC:
|
|
||||||
if (ch == TELNET_IAC)
|
|
||||||
{
|
|
||||||
telnetd_putchar(pstate, ch);
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (ch)
|
|
||||||
{
|
|
||||||
case TELNET_WILL:
|
|
||||||
pstate->tn_state = STATE_WILL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TELNET_WONT:
|
|
||||||
pstate->tn_state = STATE_WONT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TELNET_DO:
|
|
||||||
pstate->tn_state = STATE_DO;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TELNET_DONT:
|
|
||||||
pstate->tn_state = STATE_DONT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATE_WILL:
|
|
||||||
/* Reply with a DONT */
|
|
||||||
|
|
||||||
telnetd_sendopt(pstate, TELNET_DONT, ch);
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATE_WONT:
|
|
||||||
/* Reply with a DONT */
|
|
||||||
|
|
||||||
telnetd_sendopt(pstate, TELNET_DONT, ch);
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATE_DO:
|
|
||||||
/* Reply with a WONT */
|
|
||||||
|
|
||||||
telnetd_sendopt(pstate, TELNET_WONT, ch);
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATE_DONT:
|
|
||||||
/* Reply with a WONT */
|
|
||||||
|
|
||||||
telnetd_sendopt(pstate, TELNET_WONT, ch);
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATE_NORMAL:
|
|
||||||
if (ch == TELNET_IAC)
|
|
||||||
{
|
|
||||||
pstate->tn_state = STATE_IAC;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
telnetd_putchar(pstate, ch);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: telnetd_handler
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Each time a new connection to port 23 is made, a new thread is created
|
|
||||||
* that begins at this entry point. There should be exactly one argument
|
|
||||||
* and it should be the socket descriptor (+1).
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void *telnetd_handler(void *arg)
|
|
||||||
{
|
|
||||||
struct telnetd_s *pstate = (struct telnetd_s *)malloc(sizeof(struct telnetd_s));
|
|
||||||
int sockfd = (int)arg;
|
|
||||||
int ret = ERROR;
|
|
||||||
|
|
||||||
dbg("[%d] Started\n", sockfd);
|
|
||||||
|
|
||||||
/* Verify that the state structure was successfully allocated */
|
|
||||||
|
|
||||||
if (pstate)
|
|
||||||
{
|
|
||||||
/* Initialize the thread state structure */
|
|
||||||
|
|
||||||
memset(pstate, 0, sizeof(struct telnetd_s));
|
|
||||||
pstate->tn_sockfd = sockfd;
|
|
||||||
pstate->tn_state = STATE_NORMAL;
|
|
||||||
|
|
||||||
/* Start up the shell */
|
|
||||||
|
|
||||||
shell_init(pstate);
|
|
||||||
shell_start(pstate);
|
|
||||||
|
|
||||||
/* Loop processing each TELNET command */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* Read a buffer of data from the TELNET client */
|
|
||||||
|
|
||||||
ret = recv(pstate->tn_sockfd, pstate->tn_iobuffer, CONFIG_NETUTILS_IOBUFFER_SIZE, 0);
|
|
||||||
if (ret > 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Process the received TELNET data */
|
|
||||||
|
|
||||||
telnetd_dumpbuffer("Received buffer", pstate->tn_iobuffer, ret);
|
|
||||||
ret = telnetd_receive(pstate, ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (ret >= 0 && pstate->tn_state != STATE_CLOSE);
|
|
||||||
dbg("[%d] ret=%d tn_state=%d\n", sockfd, ret, pstate->tn_state);
|
|
||||||
|
|
||||||
/* End of command processing -- Clean up and exit */
|
|
||||||
|
|
||||||
free(pstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exit the task */
|
|
||||||
|
|
||||||
dbg("[%d] Exitting\n", sockfd);
|
|
||||||
close(sockfd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Public Functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: telnetd_init
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This is the main processing thread for telnetd. It never returns
|
|
||||||
* unless an error occurs
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
void telnetd_init(void)
|
|
||||||
{
|
|
||||||
/* Execute telnetd_handler on each connection to port 23 */
|
|
||||||
|
|
||||||
uip_server(HTONS(23), telnetd_handler, CONFIG_NETUTILS_TELNETDSTACKSIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: shell_prompt
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Print a prompt to the shell window.
|
|
||||||
*
|
|
||||||
* This function can be used by the shell back-end to print out a prompt
|
|
||||||
* to the shell window.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
void shell_prompt(void *handle, char *str)
|
|
||||||
{
|
|
||||||
struct telnetd_s *pstate = (struct telnetd_s *)handle;
|
|
||||||
int len = strlen(str);
|
|
||||||
|
|
||||||
strncpy(pstate->tn_iobuffer, str, len);
|
|
||||||
telnetd_dumpbuffer("Shell prompt", pstate->tn_iobuffer, len);
|
|
||||||
if (send(pstate->tn_sockfd, pstate->tn_iobuffer, len, 0) < 0)
|
|
||||||
{
|
|
||||||
dbg("[%d] Failed to send prompt\n", pstate->tn_sockfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: shell_output
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Print a string to the shell window.
|
|
||||||
*
|
|
||||||
* This function is implemented by the shell GUI / telnet server and
|
|
||||||
* can be called by the shell back-end to output a string in the
|
|
||||||
* shell window. The string is automatically appended with a linebreak.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
void shell_output(void *handle, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
struct telnetd_s *pstate = (struct telnetd_s *)handle;
|
|
||||||
unsigned len;
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vsnprintf(pstate->tn_iobuffer, CONFIG_NETUTILS_IOBUFFER_SIZE, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
len = strlen(pstate->tn_iobuffer);
|
|
||||||
if (len < CONFIG_NETUTILS_IOBUFFER_SIZE - 2)
|
|
||||||
{
|
|
||||||
pstate->tn_iobuffer[len] = ISO_cr;
|
|
||||||
pstate->tn_iobuffer[len+1] = ISO_nl;
|
|
||||||
pstate->tn_iobuffer[len+2] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
telnetd_dumpbuffer("Shell output", pstate->tn_iobuffer, len+2);
|
|
||||||
if (send(pstate->tn_sockfd, pstate->tn_iobuffer, len+2, 0) < 0)
|
|
||||||
{
|
|
||||||
dbg("[%d] Failed to send response\n", pstate->tn_sockfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: shell_quit
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Quit the shell
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
void shell_quit(void *handle, char *str)
|
|
||||||
{
|
|
||||||
struct telnetd_s *pstate = (struct telnetd_s *)handle;
|
|
||||||
pstate->tn_state = STATE_CLOSE;
|
|
||||||
}
|
|
||||||
|
|
115
netutils/telnetd/telnetd.h
Normal file
115
netutils/telnetd/telnetd.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* apps/netutils/telnetd/telnetd.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name Gregory Nutt nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __APPS_NETUTILS_TELNETD_TELNETD_H
|
||||||
|
#define __APPS_NETUTILS_TELNETD_TELNETD_H
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This structure represents the overall state of one telnet daemon instance
|
||||||
|
* (Yes, multiple telnet daemons are supported).
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct telnetd_s
|
||||||
|
{
|
||||||
|
int port; /* The port to listen on (in network byte order) */
|
||||||
|
int priority; /* The execution priority of the spawned task, */
|
||||||
|
int stacksize; /* The stack size needed by the spawned task */
|
||||||
|
main_t entry; /* The entrypoint of the task to spawn when a new
|
||||||
|
* connection is accepted. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This structure is used to passed information to telnet daemon when it
|
||||||
|
* started. It contains global information visable to all telnet daemons.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct telnetd_common_s
|
||||||
|
{
|
||||||
|
uint8_t ndaemons; /* The total number of daemons running */
|
||||||
|
sem_t startsem; /* Enforces one-at-a-time startup */
|
||||||
|
sem_t exclsem; /* Enforces exclusive access to 'minor' */
|
||||||
|
FAR struct telnetd_s *daemon; /* Describes the new daemon */
|
||||||
|
int minor; /* The next minor number to use */
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This structure is used to passed information to telnet daemon when it
|
||||||
|
* started. It contains global information visable to all telnet daemons.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern struct telnetd_common_s g_telnetdcommon;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_driver
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Create a character driver to "wrap" the telnet session. This function
|
||||||
|
* will select and return a unique path for the new telnet device.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* sd - The socket descriptor that represents the new telnet connection.
|
||||||
|
* daemon - A pointer to the structure representing the overall state of
|
||||||
|
* this instance of the telnet daemon.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* An allocated string represent the full path to the created driver. The
|
||||||
|
* receiver of the string must de-allocate this memory when it is no longer
|
||||||
|
* needed. NULL is returned on a failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
FAR char *telnetd_driver(int sd, FAR struct telnetd_s *daemon);
|
||||||
|
|
||||||
|
#endif /* __APPS_NETUTILS_TELNETD_TELNETD_H */
|
||||||
|
|
349
netutils/telnetd/telnetd_daemon.c
Normal file
349
netutils/telnetd/telnetd_daemon.c
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* netutils/telnetd/telnetd_daemon.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name Gregory Nutt nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <apps/netutils/telnetd.h>
|
||||||
|
#include <apps/netutils/uiplib.h>
|
||||||
|
|
||||||
|
#include "telnetd.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This structure is used to passed information to telnet daemon when it
|
||||||
|
* started.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct telnetd_common_s g_telnetdcommon;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_daemon
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is the Telnet daemon. It does not return (unless an
|
||||||
|
* error occurs).
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* Standard task start up arguments.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* Does not return unless an error occurs.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int telnetd_daemon(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FAR struct telnetd_s *daemon;
|
||||||
|
struct sockaddr_in myaddr;
|
||||||
|
#ifdef CONFIG_NET_HAVE_SOLINGER
|
||||||
|
struct linger ling;
|
||||||
|
#endif
|
||||||
|
socklen_t addrlen;
|
||||||
|
FAR char *devpath;
|
||||||
|
pid_t pid;
|
||||||
|
int listensd;
|
||||||
|
int acceptsd;
|
||||||
|
int drvrfd;
|
||||||
|
#ifdef CONFIG_NET_HAVE_REUSEADDR
|
||||||
|
int optval;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get daemon startup info */
|
||||||
|
|
||||||
|
daemon = g_telnetdcommon.daemon;
|
||||||
|
g_telnetdcommon.daemon = NULL;
|
||||||
|
sem_post(&g_telnetdcommon.startsem);
|
||||||
|
DEBUGASSERT(daemon != NULL);
|
||||||
|
|
||||||
|
/* Create a new TCP socket to use to listen for connections */
|
||||||
|
|
||||||
|
listensd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (listensd < 0)
|
||||||
|
{
|
||||||
|
int errval = errno;
|
||||||
|
ndbg("socket failure: %d\n", errval);
|
||||||
|
return -errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set socket to reuse address */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_HAVE_REUSEADDR
|
||||||
|
optval = 1;
|
||||||
|
if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
|
||||||
|
{
|
||||||
|
ndbg("setsockopt SO_REUSEADDR failure: %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Bind the socket to a local address */
|
||||||
|
|
||||||
|
myaddr.sin_family = AF_INET;
|
||||||
|
myaddr.sin_port = daemon->port;
|
||||||
|
myaddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
|
||||||
|
{
|
||||||
|
ndbg("bind failure: %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Listen for connections on the bound TCP socket */
|
||||||
|
|
||||||
|
if (listen(listensd, 5) < 0)
|
||||||
|
{
|
||||||
|
ndbg("listen failure %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now go silent */
|
||||||
|
|
||||||
|
#ifndef CONFIG_DEBUG
|
||||||
|
close(0);
|
||||||
|
close(1);
|
||||||
|
close(2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Begin accepting connections */
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
nvdbg("Accepting connections on port %d\n", ntohs(daemon->port));
|
||||||
|
|
||||||
|
addrlen = sizeof(struct sockaddr_in);
|
||||||
|
acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
|
||||||
|
if (acceptsd < 0)
|
||||||
|
{
|
||||||
|
ndbg("accept failed: %d\n", errno);
|
||||||
|
goto errout_with_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure to "linger" until all data is sent when the socket is closed */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_HAVE_SOLINGER
|
||||||
|
ling.l_onoff = 1;
|
||||||
|
ling.l_linger = 30; /* timeout is seconds */
|
||||||
|
if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0)
|
||||||
|
{
|
||||||
|
ndbg("setsockopt failed: %d\n", errno);
|
||||||
|
goto errout_with_acceptsd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Create a character device to "wrap" the accepted socket descriptor */
|
||||||
|
|
||||||
|
nvdbg("Creating the telnet driver\n");
|
||||||
|
devpath = telnetd_driver(acceptsd, daemon);
|
||||||
|
if (devpath < 0)
|
||||||
|
{
|
||||||
|
ndbg("telnetd_driver failed\n");
|
||||||
|
goto errout_with_acceptsd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the driver */
|
||||||
|
|
||||||
|
nvdbg("Opening the telnet driver\n");
|
||||||
|
drvrfd = open(devpath, O_RDWR);
|
||||||
|
if (drvrfd < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed to open %s: %d\n", devpath, errno);
|
||||||
|
goto errout_with_acceptsd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can now free the driver string */
|
||||||
|
|
||||||
|
free(devpath);
|
||||||
|
|
||||||
|
/* Use this driver as stdin, stdout, and stderror */
|
||||||
|
|
||||||
|
(void)dup2(drvrfd, 0);
|
||||||
|
(void)dup2(drvrfd, 1);
|
||||||
|
(void)dup2(drvrfd, 2);
|
||||||
|
|
||||||
|
/* And we can close our original driver fd */
|
||||||
|
|
||||||
|
if (drvrfd > 2)
|
||||||
|
{
|
||||||
|
close(drvrfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a task to handle the connection. The created task
|
||||||
|
* will inherit the new stdin, stdout, and stderr.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nvdbg("Starting the telnet session\n");
|
||||||
|
pid = TASK_CREATE("Telnet session", daemon->priority, daemon->stacksize,
|
||||||
|
daemon->entry, NULL);
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed start the telnet session: %d\n", errno);
|
||||||
|
goto errout_with_acceptsd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forget about the connection. */
|
||||||
|
|
||||||
|
close(0);
|
||||||
|
close(1);
|
||||||
|
close(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
errout_with_acceptsd:
|
||||||
|
close(acceptsd);
|
||||||
|
|
||||||
|
errout_with_socket:
|
||||||
|
close(listensd);
|
||||||
|
free(daemon);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_start
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Start the telnet daemon.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* config A pointer to a configuration structure that characterizes the
|
||||||
|
* telnet daemon. This configuration structure may be defined
|
||||||
|
* on the caller's stack because it is not retained by the
|
||||||
|
* daemon.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* The process ID (pid) of the new telnet daemon is returned on
|
||||||
|
* success; A negated errno is returned if the daemon was not successfully
|
||||||
|
* started.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int telnetd_start(FAR struct telnetd_config_s *config)
|
||||||
|
{
|
||||||
|
FAR struct telnetd_s *daemon;
|
||||||
|
pid_t pid;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Allocate a state structure for the new daemon */
|
||||||
|
|
||||||
|
daemon = (FAR struct telnetd_s *)malloc(sizeof(struct telnetd_s));
|
||||||
|
if (!daemon)
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the daemon structure */
|
||||||
|
|
||||||
|
daemon->port = config->d_port;
|
||||||
|
daemon->priority = config->t_priority;
|
||||||
|
daemon->stacksize = config->t_stacksize;
|
||||||
|
daemon->entry = config->t_entry;
|
||||||
|
|
||||||
|
/* Initialize the common structure if this is the first daemon */
|
||||||
|
|
||||||
|
if (g_telnetdcommon.ndaemons < 1)
|
||||||
|
{
|
||||||
|
sem_init(&g_telnetdcommon.startsem, 0, 0);
|
||||||
|
sem_init(&g_telnetdcommon.exclsem, 0, 1);
|
||||||
|
g_telnetdcommon.minor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then start the new daemon */
|
||||||
|
|
||||||
|
g_telnetdcommon.daemon = daemon;
|
||||||
|
pid = TASK_CREATE("Telnet daemon", config->d_priority, config->d_stacksize,
|
||||||
|
telnetd_daemon, NULL);
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
int errval = errno;
|
||||||
|
free(daemon);
|
||||||
|
ndbg("Failed to start the telnet daemon: %d\n", errval);
|
||||||
|
return -errval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then wait for the daemon to start and complete the handshake */
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = sem_wait(&g_telnetdcommon.startsem);
|
||||||
|
|
||||||
|
/* The only expected error condition is for sem_wait to be awakened by
|
||||||
|
* a receipt of a signal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(errno == -EINTR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
735
netutils/telnetd/telnetd_driver.c
Normal file
735
netutils/telnetd/telnetd_driver.c
Normal file
@ -0,0 +1,735 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* apps/netutils/telnetd_driver.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* This is a leverage of similar logic from uIP which has a compatible BSD
|
||||||
|
* license:
|
||||||
|
*
|
||||||
|
* Author: Adam Dunkels <adam@sics.se>
|
||||||
|
* Copyright (c) 2003, Adam Dunkels.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute, NuttX nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <nuttx/fs.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <net/psock.h>
|
||||||
|
|
||||||
|
#include <apps/netutils/telnetd.h>
|
||||||
|
#include <apps/netutils/uiplib.h>
|
||||||
|
|
||||||
|
#include "telnetd.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define ISO_nl 0x0a
|
||||||
|
#define ISO_cr 0x0d
|
||||||
|
|
||||||
|
#define TELNET_IAC 255
|
||||||
|
#define TELNET_WILL 251
|
||||||
|
#define TELNET_WONT 252
|
||||||
|
#define TELNET_DO 253
|
||||||
|
#define TELNET_DONT 254
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
/* The state of the telnet parser */
|
||||||
|
|
||||||
|
enum telnetd_state_e
|
||||||
|
{
|
||||||
|
STATE_NORMAL = 0,
|
||||||
|
STATE_IAC,
|
||||||
|
STATE_WILL,
|
||||||
|
STATE_WONT,
|
||||||
|
STATE_DO,
|
||||||
|
STATE_DONT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This structure describes the internal state of the driver */
|
||||||
|
|
||||||
|
struct telnetd_dev_s
|
||||||
|
{
|
||||||
|
sem_t td_exclsem; /* Enforces mutually exclusive access */
|
||||||
|
uint8_t td_state; /* (See telnetd_state_e) */
|
||||||
|
uint8_t td_pending; /* Number of valid, pending bytes in the rxbuffer */
|
||||||
|
uint8_t td_offset; /* Offset to the valid, pending bytes in the rxbuffer */
|
||||||
|
uint8_t td_crefs; /* The number of open references to the session */
|
||||||
|
FAR struct socket *td_psock; /* A reference to the internal socket structure */
|
||||||
|
char td_rxbuffer[CONFIG_TELNETD_IOBUFFER_SIZE];
|
||||||
|
char td_txbuffer[CONFIG_TELNETD_IOBUFFER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
/* Support functions */
|
||||||
|
|
||||||
|
#ifdef CONFIG_TELNETD_DUMPBUFFER
|
||||||
|
static inline void telnetd_dumpbuffer(FAR const char *msg,
|
||||||
|
FAR const char *buffer, unsigned int nbytes)
|
||||||
|
#else
|
||||||
|
# define telnetd_dumpbuffer(msg,buffer,nbytes)
|
||||||
|
#endif
|
||||||
|
static void telnetd_getchar(struct telnetd_dev_s *priv, uint8_t ch,
|
||||||
|
FAR char *dest, int *nread);
|
||||||
|
static ssize_t telnetd_receive(struct telnetd_dev_s *priv, FAR const char *src,
|
||||||
|
size_t srclen, FAR char *dest, size_t destlen);
|
||||||
|
static bool telnetd_putchar(struct telnetd_dev_s *priv, uint8_t ch,
|
||||||
|
int *nwritten);
|
||||||
|
static void telnetd_sendopt(struct telnetd_dev_s *priv, uint8_t option,
|
||||||
|
uint8_t value);
|
||||||
|
|
||||||
|
/* Character driver methods */
|
||||||
|
|
||||||
|
static int telnetd_open(FAR struct file *filep);
|
||||||
|
static int telnetd_close(FAR struct file *filep);
|
||||||
|
static ssize_t telnetd_read(FAR struct file *, FAR char *, size_t);
|
||||||
|
static ssize_t telnetd_write(FAR struct file *, FAR const char *, size_t);
|
||||||
|
static int telnetd_ioctl(FAR struct file *filep, int cmd,
|
||||||
|
unsigned long arg);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static const struct file_operations g_telnetdfops =
|
||||||
|
{
|
||||||
|
telnetd_open, /* open */
|
||||||
|
telnetd_close, /* close */
|
||||||
|
telnetd_read, /* read */
|
||||||
|
telnetd_write, /* write */
|
||||||
|
0, /* seek */
|
||||||
|
telnetd_ioctl /* ioctl */
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
, 0 /* poll */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_dumpbuffer
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Dump a buffer of data (debug only)
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_TELNETD_DUMPBUFFER
|
||||||
|
static inline void telnetd_dumpbuffer(FAR const char *msg,
|
||||||
|
FAR const char *buffer,
|
||||||
|
unsigned int nbytes)
|
||||||
|
{
|
||||||
|
/* CONFIG_DEBUG, CONFIG_DEBUG_VERBOSE, and CONFIG_DEBUG_NET have to be
|
||||||
|
* defined or the following does nothing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nvdbgdumpbuffer(msg, (FAR const uint8_t*)buffer, nbytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_getchar
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Get another character for the user received buffer from the RX buffer
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void telnetd_getchar(struct telnetd_dev_s *priv, uint8_t ch,
|
||||||
|
FAR char *dest, int *nread)
|
||||||
|
{
|
||||||
|
register int index;
|
||||||
|
|
||||||
|
/* Ignore carriage returns */
|
||||||
|
|
||||||
|
if (ch != ISO_cr)
|
||||||
|
{
|
||||||
|
/* Add all other characters to the destination buffer */
|
||||||
|
|
||||||
|
index = *nread;
|
||||||
|
dest[index++] = ch;
|
||||||
|
*nread = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_receive
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Process a received telenet buffer
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t telnetd_receive(struct telnetd_dev_s *priv, FAR const char *src,
|
||||||
|
size_t srclen, FAR char *dest, size_t destlen)
|
||||||
|
{
|
||||||
|
int nread;
|
||||||
|
uint8_t ch;
|
||||||
|
|
||||||
|
for (nread = 0; srclen > 0 && nread < destlen; srclen--)
|
||||||
|
{
|
||||||
|
ch = *src++;
|
||||||
|
nvdbg("ch=%02x state=%d\n", ch, priv->td_state);
|
||||||
|
|
||||||
|
switch (priv->td_state)
|
||||||
|
{
|
||||||
|
case STATE_IAC:
|
||||||
|
if (ch == TELNET_IAC)
|
||||||
|
{
|
||||||
|
telnetd_getchar(priv, ch, dest, &nread);
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (ch)
|
||||||
|
{
|
||||||
|
case TELNET_WILL:
|
||||||
|
priv->td_state = STATE_WILL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TELNET_WONT:
|
||||||
|
priv->td_state = STATE_WONT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TELNET_DO:
|
||||||
|
priv->td_state = STATE_DO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TELNET_DONT:
|
||||||
|
priv->td_state = STATE_DONT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_WILL:
|
||||||
|
/* Reply with a DONT */
|
||||||
|
|
||||||
|
telnetd_sendopt(priv, TELNET_DONT, ch);
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_WONT:
|
||||||
|
/* Reply with a DONT */
|
||||||
|
|
||||||
|
telnetd_sendopt(priv, TELNET_DONT, ch);
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_DO:
|
||||||
|
/* Reply with a WONT */
|
||||||
|
|
||||||
|
telnetd_sendopt(priv, TELNET_WONT, ch);
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_DONT:
|
||||||
|
/* Reply with a WONT */
|
||||||
|
|
||||||
|
telnetd_sendopt(priv, TELNET_WONT, ch);
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_NORMAL:
|
||||||
|
if (ch == TELNET_IAC)
|
||||||
|
{
|
||||||
|
priv->td_state = STATE_IAC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
telnetd_getchar(priv, ch, dest, &nread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We get here if (1) all of the received bytes have been processed, or
|
||||||
|
* (2) if the user's buffer has become full.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (srclen > 0)
|
||||||
|
{
|
||||||
|
/* Remember where we left off. These bytes will be returned the next
|
||||||
|
* time that telnetd_read() is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
priv->td_pending = srclen;
|
||||||
|
priv->td_offset = (src - priv->td_rxbuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* All of the received bytes were consumed */
|
||||||
|
|
||||||
|
priv->td_pending = 0;
|
||||||
|
priv->td_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_putchar
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Put another character from the user buffer to the TX buffer.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static bool telnetd_putchar(struct telnetd_dev_s *priv, uint8_t ch,
|
||||||
|
int *nread)
|
||||||
|
{
|
||||||
|
register int index;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
/* Ignore carriage returns (we will put these in automatically as necesary) */
|
||||||
|
|
||||||
|
if (ch != ISO_cr)
|
||||||
|
{
|
||||||
|
/* Add all other characters to the destination buffer */
|
||||||
|
|
||||||
|
index = *nread;
|
||||||
|
priv->td_txbuffer[index++] = ch;
|
||||||
|
|
||||||
|
/* Check for line feeds */
|
||||||
|
|
||||||
|
if (ch == ISO_nl)
|
||||||
|
{
|
||||||
|
/* Now add the carriage return */
|
||||||
|
|
||||||
|
priv->td_txbuffer[index++] = ISO_cr;
|
||||||
|
priv->td_txbuffer[index++] = '\0';
|
||||||
|
|
||||||
|
/* End of line */
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nread = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_sendopt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Send the telnet option bytes
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void telnetd_sendopt(struct telnetd_dev_s *priv, uint8_t option,
|
||||||
|
uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t optbuf[4];
|
||||||
|
optbuf[0] = TELNET_IAC;
|
||||||
|
optbuf[1] = option;
|
||||||
|
optbuf[2] = value;
|
||||||
|
optbuf[3] = 0;
|
||||||
|
|
||||||
|
telnetd_dumpbuffer("Send optbuf", optbuf, 4);
|
||||||
|
if (psock_send(priv->td_psock, optbuf, 4, 0) < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed to send TELNET_IAC\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_open
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int telnetd_open(FAR struct file *filep)
|
||||||
|
{
|
||||||
|
FAR struct inode *inode = filep->f_inode;
|
||||||
|
FAR struct telnetd_dev_s *priv = inode->i_private;
|
||||||
|
int tmp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nvdbg("td_crefs: %d\n", priv->td_crefs);
|
||||||
|
|
||||||
|
/* O_NONBLOCK is not supported */
|
||||||
|
|
||||||
|
if (filep->f_oflags & O_NONBLOCK)
|
||||||
|
{
|
||||||
|
ret = -ENOSYS;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get exclusive access to the device structures */
|
||||||
|
|
||||||
|
ret = sem_wait(&priv->td_exclsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
ret = -errno;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the count of references to the device. If this the first
|
||||||
|
* time that the driver has been opened for this device, then initialize
|
||||||
|
* the device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tmp = priv->td_crefs + 1;
|
||||||
|
if (tmp > 255)
|
||||||
|
{
|
||||||
|
/* More than 255 opens; uint8_t would overflow to zero */
|
||||||
|
|
||||||
|
ret = -EMFILE;
|
||||||
|
goto errout_with_sem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the new open count on success */
|
||||||
|
|
||||||
|
priv->td_crefs = tmp;
|
||||||
|
ret = OK;
|
||||||
|
|
||||||
|
errout_with_sem:
|
||||||
|
sem_post(&priv->td_exclsem);
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_close
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int telnetd_close(FAR struct file *filep)
|
||||||
|
{
|
||||||
|
FAR struct inode *inode = filep->f_inode;
|
||||||
|
FAR struct telnetd_dev_s *priv = inode->i_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nvdbg("td_crefs: %d\n", priv->td_crefs);
|
||||||
|
|
||||||
|
/* Get exclusive access to the device structures */
|
||||||
|
|
||||||
|
ret = sem_wait(&priv->td_exclsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
ret = -errno;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrement the references to the driver. If the reference count will
|
||||||
|
* decrement to 0, then uninitialize the driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->td_crefs > 1)
|
||||||
|
{
|
||||||
|
priv->td_crefs--;
|
||||||
|
sem_post(&priv->td_exclsem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psock_close(priv->td_psock);
|
||||||
|
sem_post(&priv->td_exclsem);
|
||||||
|
sem_destroy(&priv->td_exclsem);
|
||||||
|
free(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = OK;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_read
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t telnetd_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
||||||
|
{
|
||||||
|
FAR struct inode *inode = filep->f_inode;
|
||||||
|
FAR struct telnetd_dev_s *priv = inode->i_private;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
/* First, handle the case where there are still valid bytes left in the
|
||||||
|
* I/O buffer from the last time that read was called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->td_pending > 0)
|
||||||
|
{
|
||||||
|
FAR const char *src = &priv->td_rxbuffer[priv->td_offset];
|
||||||
|
ret = telnetd_receive(priv, src, priv->td_pending, buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a buffer of data from the telnet client */
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = psock_recv(priv->td_psock, priv->td_rxbuffer,
|
||||||
|
CONFIG_TELNETD_IOBUFFER_SIZE, 0);
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
/* Process the received telnet data */
|
||||||
|
|
||||||
|
telnetd_dumpbuffer("Received buffer", priv->td_rxbuffer, ret);
|
||||||
|
ret = telnetd_receive(priv, priv->td_rxbuffer, ret, buffer, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_write
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t telnetd_write(FAR struct file *filep, FAR const char *buffer, size_t len)
|
||||||
|
{
|
||||||
|
FAR struct inode *inode = filep->f_inode;
|
||||||
|
FAR struct telnetd_dev_s *priv = inode->i_private;
|
||||||
|
FAR const char *src = buffer;
|
||||||
|
ssize_t nsent;
|
||||||
|
ssize_t ret;
|
||||||
|
int ncopied;
|
||||||
|
char ch;
|
||||||
|
bool eol;
|
||||||
|
|
||||||
|
/* Process each character from the user buffer */
|
||||||
|
|
||||||
|
for (nsent = 0, ncopied = 0; len > 0; len--)
|
||||||
|
{
|
||||||
|
/* Get the next character from the user buffer */
|
||||||
|
|
||||||
|
ch = *src++;
|
||||||
|
|
||||||
|
/* Add the character to the TX buffer */
|
||||||
|
|
||||||
|
eol = telnetd_putchar(priv, ch, &ncopied);
|
||||||
|
|
||||||
|
/* Was that the end of a line? */
|
||||||
|
|
||||||
|
if (eol)
|
||||||
|
{
|
||||||
|
/* Yes... send the data now */
|
||||||
|
|
||||||
|
ret = psock_send(priv->td_psock, priv->td_txbuffer, ncopied, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed to send response: %s\n", priv->td_txbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the index to the beginning of the TX buffer. Remember
|
||||||
|
* the total number of bytes sent;
|
||||||
|
*/
|
||||||
|
|
||||||
|
nsent += ret;
|
||||||
|
ncopied = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send anything remaining in the TX buffer */
|
||||||
|
|
||||||
|
if (ncopied > 0)
|
||||||
|
{
|
||||||
|
ret = psock_send(priv->td_psock, priv->td_txbuffer, ncopied, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed to send response: %s\n", priv->td_txbuffer);
|
||||||
|
}
|
||||||
|
nsent += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_poll
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int telnetd_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
#if 0 /* No ioctl commands are yet supported */
|
||||||
|
struct inode *inode = filep->f_inode;
|
||||||
|
struct cdcacm_dev_s *priv = inode->i_private;
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
/* Add ioctl commands here */
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -ENOTTY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return -ENOTTY;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_poll
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if 0 /* Not used by this driver */
|
||||||
|
static int telnetd_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||||
|
bool setup)
|
||||||
|
{
|
||||||
|
FAR struct inode *inode = filep->f_inode;
|
||||||
|
FAR struct telnetd_dev_s *priv = inode->i_private;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: telnetd_driver
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Create a character driver to "wrap" the telnet session. This function
|
||||||
|
* will select and return a unique path for the new telnet device.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* sd - The socket descriptor that represents the new telnet connection.
|
||||||
|
* daemon - A pointer to the structure representing the overall state of
|
||||||
|
* this instance of the telnet daemon.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* An allocated string represent the full path to the created driver. The
|
||||||
|
* receiver of the string must de-allocate this memory when it is no longer
|
||||||
|
* needed. NULL is returned on a failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
FAR char *telnetd_driver(int sd, FAR struct telnetd_s *daemon)
|
||||||
|
{
|
||||||
|
FAR struct telnetd_dev_s *priv;
|
||||||
|
FAR char *devpath = NULL;
|
||||||
|
int minor;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Allocate instance data for this driver */
|
||||||
|
|
||||||
|
priv = (FAR struct telnetd_dev_s*)malloc(sizeof(struct telnetd_dev_s));
|
||||||
|
if (!priv)
|
||||||
|
{
|
||||||
|
ndbg("Failed to allocate the driver data structure\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the allocated driver instance */
|
||||||
|
|
||||||
|
priv->td_psock = sockfd_socket(sd);
|
||||||
|
priv->td_state = STATE_NORMAL;
|
||||||
|
priv->td_crefs = 0;
|
||||||
|
priv->td_pending = 0;
|
||||||
|
priv->td_offset = 0;
|
||||||
|
|
||||||
|
if (!priv->td_psock)
|
||||||
|
{
|
||||||
|
ndbg("Failed to convert sd=%d to a socket structure\n");
|
||||||
|
goto errout_with_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocation a unique minor device number of the telnet drvier */
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = sem_wait(&g_telnetdcommon.exclsem);
|
||||||
|
if (ret < 0 && errno != -EINTR)
|
||||||
|
{
|
||||||
|
goto errout_with_dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
|
|
||||||
|
minor = g_telnetdcommon.minor;
|
||||||
|
g_telnetdcommon.minor++;
|
||||||
|
sem_post(&g_telnetdcommon.exclsem);
|
||||||
|
|
||||||
|
/* Create a path and name for the driver. */
|
||||||
|
|
||||||
|
ret = asprintf(&devpath, "/dev/telnetd%d", minor);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed to allocate the driver path\n");
|
||||||
|
goto errout_with_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register the driver */
|
||||||
|
|
||||||
|
ret = register_driver(devpath, &g_telnetdfops, 0666, priv);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
ndbg("Failed to register the driver %s: %d\n", ret);
|
||||||
|
goto errout_with_devpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the path to the new telnet driver */
|
||||||
|
|
||||||
|
return devpath;
|
||||||
|
|
||||||
|
errout_with_devpath:
|
||||||
|
free(devpath);
|
||||||
|
errout_with_dev:
|
||||||
|
free(priv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user