diff options
27 files changed, 2373 insertions, 782 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 77b92d12c..1179e2614 100755 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -164,3 +164,13 @@ a USB serial console, then NSH needs to wait until the USB console is connected and available. * 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. diff --git a/apps/examples/Makefile b/apps/examples/Makefile index c2e5fe3de..3847c2b12 100644 --- a/apps/examples/Makefile +++ b/apps/examples/Makefile @@ -40,8 +40,8 @@ SUBDIRS = adc buttons can composite dhcpd ftpc hello helloxx hidkbd igmp \ lcdrw mm mount nettest nsh null nx nxffs nxflat nxhello nximage \ nxlines nxtext ostest pashello pipe poll pwm rgmp romfs sendmail \ - serloop thttpd tiff touchscreen udp uip usbserial usbstorage usbterm \ - wget wlan + serloop telnetd thttpd tiff touchscreen udp uip usbserial \ + usbstorage usbterm wget wlan # Sub-directories that might need context setup. Directories may need # 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 ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) -CNTXTDIRS += adc can composite dhcpd nettest +CNTXTDIRS += adc can composite dhcpd nettest telnetd endif ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y) diff --git a/apps/examples/README.txt b/apps/examples/README.txt index 3dc8bdfb2..b14d19b84 100644 --- a/apps/examples/README.txt +++ b/apps/examples/README.txt @@ -894,6 +894,28 @@ examples/serloop Use C buffered I/O (getchar/putchar) vs. raw console I/O (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 ^^^^^^^^^^^^^^^ diff --git a/apps/examples/telnetd/Makefile b/apps/examples/telnetd/Makefile new file mode 100644 index 000000000..dcb6615cc --- /dev/null +++ b/apps/examples/telnetd/Makefile @@ -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 diff --git a/apps/examples/telnetd/README.txt b/apps/examples/telnetd/README.txt new file mode 100644 index 000000000..ebc9684ca --- /dev/null +++ b/apps/examples/telnetd/README.txt @@ -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. diff --git a/apps/examples/telnetd/shell.c b/apps/examples/telnetd/shell.c new file mode 100644 index 000000000..69f348615 --- /dev/null +++ b/apps/examples/telnetd/shell.c @@ -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; +} diff --git a/apps/examples/telnetd/shell.h b/apps/examples/telnetd/shell.h new file mode 100644 index 000000000..96aab1319 --- /dev/null +++ b/apps/examples/telnetd/shell.h @@ -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 */ diff --git a/apps/include/netutils/telnetd.h b/apps/include/netutils/telnetd.h index 9d3d6feaf..37e7dfd4f 100644 --- a/apps/include/netutils/telnetd.h +++ b/apps/include/netutils/telnetd.h @@ -1,14 +1,8 @@ /**************************************************************************** * include/apps/netutils/telnetd.h * - * Copyright (C) 2007, 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. + * Copyright (C) 2007, 2011-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 @@ -17,35 +11,83 @@ * 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 + * 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 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. + * 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_H -#define __APPS_NETUTILS_TELNETD_H +#ifndef __APPS_INCLUDE_NETUTILS_TELNETD_H +#define __APPS_INCLUDE_NETUTILS_TELNETD_H /**************************************************************************** * 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 @@ -58,13 +100,29 @@ extern "C" { #define EXTERN extern #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 #ifdef __cplusplus } #endif - -#endif /* __APPS_NETUTILS_TELNETD_H */ +#endif /* __APPS_INCLUDE_NETUTILS_TELNETD_H */ diff --git a/apps/netutils/README.txt b/apps/netutils/README.txt index 2059b569e..ea9dbd5c3 100644 --- a/apps/netutils/README.txt +++ b/apps/netutils/README.txt @@ -9,7 +9,6 @@ include: dhcpc - Dynamic Host Configuration Protocol (DHCP) client resolv - uIP DNS resolver smtp - Simple Mail Transfer Protocol (SMTP) client - telnetd - TELNET server webclient - HTTP web client webserver - HTTP web server @@ -21,6 +20,12 @@ highly influenced by uIP) include: dhcpd - Dynamic Host Configuration Protocol (DHCP) server 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 thttpd - This is a port of Jef Poskanzer's THTTPD HTPPD server. See http://acme.com/software/thttpd/. diff --git a/apps/netutils/telnetd/Makefile b/apps/netutils/telnetd/Makefile index cba7f0c70..fac6df571 100644 --- a/apps/netutils/telnetd/Makefile +++ b/apps/netutils/telnetd/Makefile @@ -1,8 +1,8 @@ ############################################################################ # apps/netutils/telnetd/Makefile # -# Copyright (C) 2011 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# Copyright (C) 2011-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 @@ -43,7 +43,7 @@ ASRCS = CSRCS = ifeq ($(CONFIG_NET_TCP),y) -CSRCS += telnetd.c shell.c +CSRCS += telnetd_daemon.c telnetd_driver.c endif AOBJS = $(ASRCS:.S=$(OBJEXT)) diff --git a/apps/netutils/telnetd/README.txt b/apps/netutils/telnetd/README.txt index 24fcba7d5..367cef0a2 100644 --- a/apps/netutils/telnetd/README.txt +++ b/apps/netutils/telnetd/README.txt @@ -1,7 +1,4 @@ -This directory is here for historical reasons. Nothing contained in this -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. +README.txt +^^^^^^^^^^ +This directly contains a generic Telnet daemon. diff --git a/apps/netutils/telnetd/shell.c b/apps/netutils/telnetd/shell.c deleted file mode 100644 index 93fd11601..000000000 --- a/apps/netutils/telnetd/shell.c +++ /dev/null @@ -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); -} diff --git a/apps/netutils/telnetd/shell.h b/apps/netutils/telnetd/shell.h deleted file mode 100644 index 32325fe17..000000000 --- a/apps/netutils/telnetd/shell.h +++ /dev/null @@ -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__ */ diff --git a/apps/netutils/telnetd/telnetd.c b/apps/netutils/telnetd/telnetd.c deleted file mode 100644 index ccadd60dd..000000000 --- a/apps/netutils/telnetd/telnetd.c +++ /dev/null @@ -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; -} - diff --git a/apps/netutils/telnetd/telnetd.h b/apps/netutils/telnetd/telnetd.h new file mode 100644 index 000000000..957c6c550 --- /dev/null +++ b/apps/netutils/telnetd/telnetd.h @@ -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 */ + diff --git a/apps/netutils/telnetd/telnetd_daemon.c b/apps/netutils/telnetd/telnetd_daemon.c new file mode 100644 index 000000000..7165ee49d --- /dev/null +++ b/apps/netutils/telnetd/telnetd_daemon.c @@ -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; +} diff --git a/apps/netutils/telnetd/telnetd_driver.c b/apps/netutils/telnetd/telnetd_driver.c new file mode 100644 index 000000000..efa693cdb --- /dev/null +++ b/apps/netutils/telnetd/telnetd_driver.c @@ -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; +} + + + diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 271d7fb89..72024519b 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -2408,3 +2408,5 @@ sub-directory: By making libboard.a a "phony" target, libboard.a should always rebuilt (the end result is worth the small increase in build time) (submitted by Mike Smith). + * include/net/psock.h: A new low level socket interface that allows the OS + to use the socket interface without having a socket descriptor. diff --git a/nuttx/include/net/psock.h b/nuttx/include/net/psock.h new file mode 100644 index 000000000..26691d5df --- /dev/null +++ b/nuttx/include/net/psock.h @@ -0,0 +1,312 @@ +/**************************************************************************** + * include/net/psock.h + * + * 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 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. + * + ****************************************************************************/ + +#ifndef __NET_PSOCK_H +#define __NET_PSOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> + +#ifdef CONFIG_NET + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Function: sockfd_socket + * + * Description: + * Given a socket descriptor, return the underly NuttX-specific socket + * structure. + * + * Parameters: + * psock Socket instance + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +struct socket; +EXTERN FAR struct socket *sockfd_socket(int sockfd); + +/**************************************************************************** + * Function: psock_close + * + * Description: + * Performs the close operation on a socket instance + * + * Parameters: + * psock Socket instance + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +struct socket; +EXTERN int psock_close(FAR struct socket *psock); + +/**************************************************************************** + * Function: psock_send + * + * Description: + * The send() call may be used only when the socket is in a connected state + * (so that the intended recipient is known). The only difference between + * send() and write() is the presence of flags. With zero flags parameter, + * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is + * equivalent to sendto(sockfd,buf,len,flags,NULL,0). + * + * Parameters: + * psock And instance of the internal socket structure. + * buf Data to send + * len Length of data to send + * flags Send flags + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and the requested operation + * would block. + * EBADF + * An invalid descriptor was specified. + * ECONNRESET + * Connection reset by peer. + * EDESTADDRREQ + * The socket is not connection-mode, and no peer address is set. + * EFAULT + * An invalid user space address was specified for a parameter. + * EINTR + * A signal occurred before any data was transmitted. + * EINVAL + * Invalid argument passed. + * EISCONN + * The connection-mode socket was connected already but a recipient + * was specified. (Now either this error is returned, or the recipient + * specification is ignored.) + * EMSGSIZE + * The socket type requires that message be sent atomically, and the + * size of the message to be sent made this impossible. + * ENOBUFS + * The output queue for a network interface was full. This generally + * indicates that the interface has stopped sending, but may be + * caused by transient congestion. + * ENOMEM + * No memory available. + * ENOTCONN + * The socket is not connected, and no target has been given. + * ENOTSOCK + * The argument s is not a socket. + * EOPNOTSUPP + * Some bit in the flags argument is inappropriate for the socket + * type. + * EPIPE + * The local end has been shut down on a connection oriented socket. + * In this case the process will also receive a SIGPIPE unless + * MSG_NOSIGNAL is set. + * + * Assumptions: + * + ****************************************************************************/ + +struct socket; +EXTERN ssize_t psock_send(FAR struct socket *psock, const void *buf, + size_t len, int flags); + +/**************************************************************************** + * Function: psock_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and the requested operation + * would block. + * EBADF + * An invalid descriptor was specified. + * ECONNRESET + * Connection reset by peer. + * EDESTADDRREQ + * The socket is not connection-mode, and no peer address is set. + * EFAULT + * An invalid user space address was specified for a parameter. + * EINTR + * A signal occurred before any data was transmitted. + * EINVAL + * Invalid argument passed. + * EISCONN + * The connection-mode socket was connected already but a recipient + * was specified. (Now either this error is returned, or the recipient + * specification is ignored.) + * EMSGSIZE + * The socket type requires that message be sent atomically, and the + * size of the message to be sent made this impossible. + * ENOBUFS + * The output queue for a network interface was full. This generally + * indicates that the interface has stopped sending, but may be + * caused by transient congestion. + * ENOMEM + * No memory available. + * ENOTCONN + * The socket is not connected, and no target has been given. + * ENOTSOCK + * The argument s is not a socket. + * EOPNOTSUPP + * Some bit in the flags argument is inappropriate for the socket + * type. + * EPIPE + * The local end has been shut down on a connection oriented socket. + * In this case the process will also receive a SIGPIPE unless + * MSG_NOSIGNAL is set. + * + * Assumptions: + * + ****************************************************************************/ + +struct socket; +struct sockaddr; +EXTERN ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen); + +/**************************************************************************** + * Function: psock_recvfrom + * + * Description: + * recvfrom() receives messages from a socket, and may be used to receive + * data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN + * The socket is marked non-blocking and the receive operation would block, + * or a receive timeout had been set and the timeout expired before data + * was received. + * EBADF + * The argument sockfd is an invalid descriptor. + * ECONNREFUSED + * A remote host refused to allow the network connection (typically because + * it is not running the requested service). + * EFAULT + * The receive buffer pointer(s) point outside the process's address space. + * EINTR + * The receive was interrupted by delivery of a signal before any data were + * available. + * EINVAL + * Invalid argument passed. + * ENOMEM + * Could not allocate memory. + * ENOTCONN + * The socket is associated with a connection-oriented protocol and has + * not been connected. + * ENOTSOCK + * The argument sockfd does not refer to a socket. + * + * Assumptions: + * + ****************************************************************************/ + +struct socket; +struct sockaddr; +EXTERN ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags,FAR struct sockaddr *from, + FAR socklen_t *fromlen); + +#define psock_recv(psock,buf,len,flags) psock_recvfrom(psock,buf,len,flags,NULL,0) + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* CONFIG_NET */ +#endif /* __NET_PSOCK_H */ diff --git a/nuttx/net/net_close.c b/nuttx/net/net_close.c index ca2e2999c..cf1c36bfe 100644 --- a/nuttx/net/net_close.c +++ b/nuttx/net/net_close.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/net_close.c * - * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-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 @@ -199,10 +199,10 @@ static inline void netclose_disconnect(FAR struct socket *psock) ****************************************************************************/ /**************************************************************************** - * Function: net_closesocket + * Function: psock_close * * Description: - * Performs the close operation on asocket instance + * Performs the close operation on a socket instance * * Parameters: * psock Socket instance @@ -214,7 +214,7 @@ static inline void netclose_disconnect(FAR struct socket *psock) * ****************************************************************************/ -int net_closesocket(FAR struct socket *psock) +int psock_close(FAR struct socket *psock) { int err; @@ -324,7 +324,7 @@ errout: int net_close(int sockfd) { - return net_closesocket(sockfd_socket(sockfd)); + return psock_close(sockfd_socket(sockfd)); } #endif /* CONFIG_NET */ diff --git a/nuttx/net/net_internal.h b/nuttx/net/net_internal.h index e3498cd44..4046070ab 100644 --- a/nuttx/net/net_internal.h +++ b/nuttx/net/net_internal.h @@ -1,8 +1,8 @@ /**************************************************************************** * net/net_internal.h * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-2009, 2011-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 @@ -48,6 +48,7 @@ #include <time.h> #include <nuttx/net.h> +#include <net/psock.h> #include <net/uip/uip.h> /**************************************************************************** @@ -157,7 +158,7 @@ EXTERN FAR struct socket *sockfd_socket(int sockfd); /* net_close.c ***************************************************************/ -EXTERN int net_closesocket(FAR struct socket *psock); +EXTERN int psock_close(FAR struct socket *psock); /* sockopt support ***********************************************************/ @@ -206,6 +207,11 @@ EXTERN void arptimer_init(void); # define arptimer_init() #endif +/* send.c ********************************************************************/ + +EXTERN ssize_t psock_send(FAR struct socket *psock, const void *buf, + size_t len, int flags); + #undef EXTERN #if defined(__cplusplus) } diff --git a/nuttx/net/net_poll.c b/nuttx/net/net_poll.c index fa63c8d45..da953fc9f 100644 --- a/nuttx/net/net_poll.c +++ b/nuttx/net/net_poll.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/net_poll.c * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2008-2009, 2011-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 diff --git a/nuttx/net/net_sockets.c b/nuttx/net/net_sockets.c index a1e8f15b0..31c1709d7 100644 --- a/nuttx/net/net_sockets.c +++ b/nuttx/net/net_sockets.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/net_sockets.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-2009, 2011-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 @@ -186,7 +186,7 @@ int net_releaselist(FAR struct socketlist *list) if (crefs <= 0) { /* Close each open socket in the list - * REVISIT: net_closesocket() will attempt to use semaphores. + * REVISIT: psock_close() will attempt to use semaphores. * If we actually are in the IDLE thread, then could this cause * problems? Probably not, it the task has exited and crefs is * zero, then there probably could not be a contender for the @@ -198,7 +198,7 @@ int net_releaselist(FAR struct socketlist *list) FAR struct socket *psock = &list->sl_sockets[ndx]; if (psock->s_crefs > 0) { - (void)net_closesocket(psock); + (void)psock_close(psock); } } diff --git a/nuttx/net/recv.c b/nuttx/net/recv.c index 3d5b82f2c..1571a7377 100644 --- a/nuttx/net/recv.c +++ b/nuttx/net/recv.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/recv.c * - * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007, 2008, 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 diff --git a/nuttx/net/recvfrom.c b/nuttx/net/recvfrom.c index d9039b91b..f1f08d66d 100644 --- a/nuttx/net/recvfrom.c +++ b/nuttx/net/recvfrom.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/recvfrom.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-2009, 2011-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 @@ -988,7 +988,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, ****************************************************************************/ /**************************************************************************** - * Function: recvfrom + * Function: psock_recvfrom * * Description: * recvfrom() receives messages from a socket, and may be used to receive @@ -1000,7 +1000,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, * on return to indicate the actual size of the address stored there. * * Parameters: - * sockfd Socket descriptor of socket + * psock A pointer to a NuttX-specific, internal socket structure * buf Buffer to receive data * len Length of buffer * flags Receive flags @@ -1039,11 +1039,10 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, * ****************************************************************************/ -ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, - FAR struct sockaddr *from, FAR socklen_t *fromlen) +ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + int flags,FAR struct sockaddr *from, + FAR socklen_t *fromlen) { - FAR struct socket *psock; - #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) #ifdef CONFIG_NET_IPv6 FAR struct sockaddr_in6 *infrom = (struct sockaddr_in6 *)from; @@ -1065,10 +1064,8 @@ ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, } #endif - /* Get the underlying socket structure */ /* Verify that the sockfd corresponds to valid, allocated socket */ - psock = sockfd_socket(sockfd); if (!psock || psock->s_crefs <= 0) { err = EBADF; @@ -1136,4 +1133,70 @@ errout: return ERROR; } +/**************************************************************************** + * Function: recvfrom + * + * Description: + * recvfrom() receives messages from a socket, and may be used to receive + * data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN + * The socket is marked non-blocking and the receive operation would block, + * or a receive timeout had been set and the timeout expired before data + * was received. + * EBADF + * The argument sockfd is an invalid descriptor. + * ECONNREFUSED + * A remote host refused to allow the network connection (typically because + * it is not running the requested service). + * EFAULT + * The receive buffer pointer(s) point outside the process's address space. + * EINTR + * The receive was interrupted by delivery of a signal before any data were + * available. + * EINVAL + * Invalid argument passed. + * ENOMEM + * Could not allocate memory. + * ENOTCONN + * The socket is associated with a connection-oriented protocol and has + * not been connected. + * ENOTSOCK + * The argument sockfd does not refer to a socket. + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, + FAR struct sockaddr *from, FAR socklen_t *fromlen) +{ + FAR struct socket *psock; + + /* Get the underlying socket structure */ + + psock = sockfd_socket(sockfd); + + /* Then let psock_recvfrom() do all of the work */ + + return psock_recvfrom(psock, buf, len, flags, from, fromlen); +} + #endif /* CONFIG_NET */ diff --git a/nuttx/net/send.c b/nuttx/net/send.c index 4eceddffc..087b43351 100644 --- a/nuttx/net/send.c +++ b/nuttx/net/send.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/send.c * - * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-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 @@ -336,7 +336,7 @@ end_wait: ****************************************************************************/ /**************************************************************************** - * Function: send + * Function: psock_send * * Description: * The send() call may be used only when the socket is in a connected state @@ -346,7 +346,7 @@ end_wait: * equivalent to sendto(sockfd,buf,len,flags,NULL,0). * * Parameters: - * sockfd Socket descriptor of socket + * psock And instance of the internal socket structure. * buf Data to send * len Length of data to send * flags Send flags @@ -399,9 +399,8 @@ end_wait: * ****************************************************************************/ -ssize_t send(int sockfd, const void *buf, size_t len, int flags) +ssize_t psock_send(FAR struct socket *psock, const void *buf, size_t len, int flags) { - FAR struct socket *psock = sockfd_socket(sockfd); struct send_s state; uip_lock_t save; int err; @@ -525,4 +524,73 @@ errout: return ERROR; } +/**************************************************************************** + * Function: send + * + * Description: + * The send() call may be used only when the socket is in a connected state + * (so that the intended recipient is known). The only difference between + * send() and write() is the presence of flags. With zero flags parameter, + * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is + * equivalent to sendto(sockfd,buf,len,flags,NULL,0). + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Data to send + * len Length of data to send + * flags Send flags + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and the requested operation + * would block. + * EBADF + * An invalid descriptor was specified. + * ECONNRESET + * Connection reset by peer. + * EDESTADDRREQ + * The socket is not connection-mode, and no peer address is set. + * EFAULT + * An invalid user space address was specified for a parameter. + * EINTR + * A signal occurred before any data was transmitted. + * EINVAL + * Invalid argument passed. + * EISCONN + * The connection-mode socket was connected already but a recipient + * was specified. (Now either this error is returned, or the recipient + * specification is ignored.) + * EMSGSIZE + * The socket type requires that message be sent atomically, and the + * size of the message to be sent made this impossible. + * ENOBUFS + * The output queue for a network interface was full. This generally + * indicates that the interface has stopped sending, but may be + * caused by transient congestion. + * ENOMEM + * No memory available. + * ENOTCONN + * The socket is not connected, and no target has been given. + * ENOTSOCK + * The argument s is not a socket. + * EOPNOTSUPP + * Some bit in the flags argument is inappropriate for the socket + * type. + * EPIPE + * The local end has been shut down on a connection oriented socket. + * In this case the process will also receive a SIGPIPE unless + * MSG_NOSIGNAL is set. + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t send(int sockfd, const void *buf, size_t len, int flags) +{ + return psock_send(sockfd_socket(sockfd), buf, len, flags); +} + #endif /* CONFIG_NET && CONFIG_NET_TCP */ diff --git a/nuttx/net/sendto.c b/nuttx/net/sendto.c index 8e2bf29b2..4e1f9015f 100644 --- a/nuttx/net/sendto.c +++ b/nuttx/net/sendto.c @@ -1,8 +1,8 @@ /**************************************************************************** * net/sendto.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-2009, 2011-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 @@ -157,7 +157,7 @@ static uint16_t sendto_interrupt(struct uip_driver_s *dev, void *conn, ****************************************************************************/ /**************************************************************************** - * Function: sendto + * Function: psock_sendto * * Description: * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) @@ -166,7 +166,7 @@ static uint16_t sendto_interrupt(struct uip_driver_s *dev, void *conn, * returned when the socket was not actually connected. * * Parameters: - * sockfd Socket descriptor of socket + * psock A pointer to a NuttX-specific, internal socket structure * buf Data to send * len Length of data to send * flags Send flags @@ -221,10 +221,10 @@ static uint16_t sendto_interrupt(struct uip_driver_s *dev, void *conn, * ****************************************************************************/ -ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *to, socklen_t tolen) +ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen) { - FAR struct socket *psock; #ifdef CONFIG_NET_UDP FAR struct uip_udp_conn *conn; #ifdef CONFIG_NET_IPv6 @@ -245,7 +245,7 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, if (!to || !tolen) { #ifdef CONFIG_NET_TCP - return send(sockfd, buf, len, flags); + return psock_send(psock, buf, len, flags); #else err = EINVAL; goto errout; @@ -264,10 +264,8 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, goto errout; } - /* Get the underlying socket structure */ - /* Verify that the sockfd corresponds to valid, allocated socket */ + /* Verify that the psock corresponds to valid, allocated socket */ - psock = sockfd_socket(sockfd); if (!psock || psock->s_crefs <= 0) { err = EBADF; @@ -369,4 +367,83 @@ errout: return ERROR; } +/**************************************************************************** + * Function: sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and the requested operation + * would block. + * EBADF + * An invalid descriptor was specified. + * ECONNRESET + * Connection reset by peer. + * EDESTADDRREQ + * The socket is not connection-mode, and no peer address is set. + * EFAULT + * An invalid user space address was specified for a parameter. + * EINTR + * A signal occurred before any data was transmitted. + * EINVAL + * Invalid argument passed. + * EISCONN + * The connection-mode socket was connected already but a recipient + * was specified. (Now either this error is returned, or the recipient + * specification is ignored.) + * EMSGSIZE + * The socket type requires that message be sent atomically, and the + * size of the message to be sent made this impossible. + * ENOBUFS + * The output queue for a network interface was full. This generally + * indicates that the interface has stopped sending, but may be + * caused by transient congestion. + * ENOMEM + * No memory available. + * ENOTCONN + * The socket is not connected, and no target has been given. + * ENOTSOCK + * The argument s is not a socket. + * EOPNOTSUPP + * Some bit in the flags argument is inappropriate for the socket + * type. + * EPIPE + * The local end has been shut down on a connection oriented socket. + * In this case the process will also receive a SIGPIPE unless + * MSG_NOSIGNAL is set. + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t sendto(int sockfd, FAR const void *buf, size_t len, int flags, + FAR const struct sockaddr *to, socklen_t tolen) +{ + FAR struct socket *psock; + + /* Get the underlying socket structure */ + + psock = sockfd_socket(sockfd); + + /* And let psock_sendto do all of the work */ + + return psock_sendto(psock, buf, len, flags, to, tolen); +} + #endif /* CONFIG_NET */ |