diff --git a/include/system/readline.h b/include/system/readline.h index 8020cf2c9..a2ef10bbf 100644 --- a/include/system/readline.h +++ b/include/system/readline.h @@ -216,11 +216,7 @@ ssize_t readline(FAR char *buf, int buflen, FILE *instream, FILE *outstream); * ****************************************************************************/ -#if CONFIG_NFILE_STREAMS > 0 -# define std_readline(b,s) readline(b,s,stdin,stdout) -#else -ssize_t std_readline(FAR char *buf, int buflen); -#endif +#define std_readline(b,s) readline(b,s,stdin,stdout) #undef EXTERN #ifdef __cplusplus diff --git a/netutils/telnetc/Kconfig b/netutils/telnetc/Kconfig new file mode 100644 index 000000000..ab3d42a7f --- /dev/null +++ b/netutils/telnetc/Kconfig @@ -0,0 +1,20 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config NETUTILS_TELNETC + bool "Telnet client library" + default n + depends on NET && NET_TCP + ---help--- + Enable support for the libtelnet. This is a public domain + Telnet client library available from https://github.com/seanmiddleditch/libtelnet + modified for use with NuttX. Original Authors: + + Sean Middleditch + Jack Kelly + Katherine Flavel + +if NETUTILS_TELNETC +endif diff --git a/netutils/telnetc/Make.defs b/netutils/telnetc/Make.defs new file mode 100644 index 000000000..1d5a07ee0 --- /dev/null +++ b/netutils/telnetc/Make.defs @@ -0,0 +1,39 @@ +# apps/netutils/telnetc/Make.defs +# Adds selected applications to apps/ build +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# +############################################################################ + +ifeq ($(CONFIG_NETUTILS_TELNETC),y) +CONFIGURED_APPS += netutils/telnetc +endif + diff --git a/netutils/telnetc/Makefile b/netutils/telnetc/Makefile new file mode 100644 index 000000000..138fedc08 --- /dev/null +++ b/netutils/telnetc/Makefile @@ -0,0 +1,104 @@ +############################################################################ +# apps/netutils/telnetc/Makefile +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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 + +# Telnet daemon + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS += telnetc.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean preconfig + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + $(Q) touch .built + +install: + +context: + +.depend: Makefile $(SRCS) + $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + $(Q) touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +preconfig: + +-include Make.dep diff --git a/netutils/telnetc/telnetc.c b/netutils/telnetc/telnetc.c index a5ee4e38e..d27e93ced 100644 --- a/netutils/telnetc/telnetc.c +++ b/netutils/telnetc/telnetc.c @@ -249,7 +249,7 @@ enum telnet_error_u _init_zlib(struct telnet_s *telnet, int deflate, if ((z = (z_stream *) calloc(1, sizeof(z_stream))) == 0) { return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal, - "malloc() failed: %s", strerror(errno)); + "malloc() failed: %d", errno); } /* Initialize */ @@ -445,7 +445,7 @@ static inline void _set_rfc1143(struct telnet_s *telnet, unsigned char telopt, if (qtmp == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "realloc() failed: %s", strerror(errno)); + "realloc() failed: %d", errno); return; } @@ -758,7 +758,7 @@ static int _environ_telnet(struct telnet_s *telnet, unsigned char type, if (values == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "calloc() failed: %s", strerror(errno)); + "calloc() failed: %d", errno); return 0; } @@ -901,7 +901,7 @@ static int _mssp_telnet(struct telnet_s *telnet, char *buffer, size_t size) if (values == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "calloc() failed: %s", strerror(errno)); + "calloc() failed: %d", errno); return 0; } @@ -992,7 +992,7 @@ static int _zmp_telnet(struct telnet_s *telnet, const char *buffer, size_t size) if ((argv = (char **)calloc(argc, sizeof(char *))) == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "calloc() failed: %s", strerror(errno)); + "calloc() failed: %d", errno); return 0; } @@ -1053,7 +1053,7 @@ static int _ttype_telnet(struct telnet_s *telnet, const char *buffer, if ((name = (char *)malloc(size)) == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "malloc() failed: %s", strerror(errno)); + "malloc() failed: %d", errno); return 0; } @@ -1980,7 +1980,7 @@ int telnet_vprintf(struct telnet_s *telnet, const char *fmt, va_list va) if (output == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "malloc() failed: %s", strerror(errno)); + "malloc() failed: %d", errno); return -1; } @@ -2109,7 +2109,7 @@ int telnet_raw_vprintf(struct telnet_s *telnet, const char *fmt, va_list va) if (output == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, - "malloc() failed: %s", strerror(errno)); + "malloc() failed: %d", errno); return -1; } diff --git a/system/telnet/.gitignore b/system/telnet/.gitignore new file mode 100644 index 000000000..fa1ec7579 --- /dev/null +++ b/system/telnet/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/system/telnet/Kconfig b/system/telnet/Kconfig new file mode 100644 index 000000000..51cb9f72e --- /dev/null +++ b/system/telnet/Kconfig @@ -0,0 +1,61 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig SYSTEM_TELNET_CHATD + bool "Telnet chat deamon" + default n + depends on NET && NET_TCP + select NETUTILS_TELNETC + ---help--- + Enable the Telnet Chat daemon. + +if SYSTEM_TELNET_CHATD + +config SYSTEM_TELNET_CHATD_PROGNAME + string "Chat daemon program name" + default "chatd" + depends on BUILD_KERNEL + +if NSH_BUILTIN_APPS + +config SYSTEM_TELNET_CHATD_STACKSIZE + int "Chat daemon stacksize" + default 2048 + +config SYSTEM_TELNET_CHATD_PRIORITY + int "Chat daemon priority" + default 100 + +endif # NSH_BUILTIN_APPS +endif # SYSTEM_TELNET_CHATD + +menuconfig SYSTEM_TELNET_CLIENT + bool "Telnet client" + default n + depends on NET && NET_TCP + select NETUTILS_TELNETC + select SYSTEM_READLINE + ---help--- + Enable the Telnet client program. + +if SYSTEM_TELNET_CLIENT + +config SYSTEM_TELNET_CLIENT_PROGNAME + string "Telnet client program name" + default "chatd" + depends on BUILD_KERNEL + +if NSH_BUILTIN_APPS + +config SYSTEM_TELNET_CLIENT_STACKSIZE + int "Telnet client stacksize" + default 2048 + +config SYSTEM_TELNET_CLIENT_PRIORITY + int "Telnet client priority" + default 100 + +endif # NSH_BUILTIN_APPS +endif # SYSTEM_TELNET_CLIENT diff --git a/system/telnet/Make.defs b/system/telnet/Make.defs new file mode 100644 index 000000000..cb9c7a480 --- /dev/null +++ b/system/telnet/Make.defs @@ -0,0 +1,41 @@ +############################################################################ +# apps/system/usbmsc/Make.defs +# Adds selected applications to apps/ build +# +# Copyright (C) 2016 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# +############################################################################ + +ifeq ($(CONFIG_SYSTEM_TELNET_CHATD),y) +CONFIGURED_APPS += system/telnet +else ifeq ($(CONFIG_SYSTEM_TELNET_CLIENT),y) +CONFIGURED_APPS += system/telnet +endif diff --git a/system/telnet/Makefile b/system/telnet/Makefile new file mode 100644 index 000000000..0ff663985 --- /dev/null +++ b/system/telnet/Makefile @@ -0,0 +1,205 @@ +############################################################################ +# apps/system/telnet/Makefile +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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 + +# Telnet Programs + +ifeq ($(CONFIG_SYSTEM_TELNET_CHATD),y) + +# Chatd files + +CHATD_CSRCS = +CHATD_MAINSRC = telnet_chatd.c + +CHATD_COBJS = $(CHATD_CSRCS:.c=$(OBJEXT)) +CHATD_MAINOBJ = $(CHATD_MAINSRC:.c=$(OBJEXT)) + +# Chatd Application Info + +CONFIG_SYSTEM_TELNET_CHATD_PROGNAME ?= chatd +CONFIG_SYSTEM_TELNET_CHATD_PRIORITY ?= 100 +CONFIG_SYSTEM_TELNET_CHATD_STACKSIZE ?= 2048 + +CHATD_MAINNAME = chatd_main +CHATD_APPNAME = chatd +CHATD_PROGNAME = $(CONFIG_SYSTEM_TELNET_CHATD_PROGNAME) +CHATD_PRIORITY = $(CONFIG_SYSTEM_TELNET_CHATD_PRIORITY) +CHATD_STACKSIZE = $(CONFIG_SYSTEM_TELNET_CHATD_STACKSIZE) + +endif + +ifeq ($(CONFIG_SYSTEM_TELNET_CLIENT),y) + +# Telnet client files + +CLIENT_CSRCS = +CLIENT_MAINSRC = telnet_client.c + +CLIENT_COBJS = $(CLIENT_CSRCS:.c=$(OBJEXT)) +CLIENT_MAINOBJ = $(CLIENT_MAINSRC:.c=$(OBJEXT)) + +# Telnet client Application Info + +CONFIG_SYSTEM_TELNET_CLIENT_PROGNAME ?= tcpclient +CONFIG_SYSTEM_TELNET_CLIENT_PRIORITY ?= 100 +CONFIG_SYSTEM_TELNET_CLIENT_STACKSIZE ?= 2048 + +CLIENT_MAINNAME = telnet_main +CLIENT_APPNAME = telnet +CLIENT_PROGNAME = $(CONFIG_SYSTEM_TELNET_CLIENT_PROGNAME) +CLIENT_PRIORITY = $(CONFIG_SYSTEM_TELNET_CLIENT_PRIORITY) +CLIENT_STACKSIZE = $(CONFIG_SYSTEM_TELNET_CLIENT_STACKSIZE) + +endif + +# All programns + +TARG_SRCS = $(CHATD_CRCS) $(CHATD_MAINSRC) $(CLIENT_CSRCS) $(CLIENT_MAINSRC) +TARG_OBJS = $(CHATD_COBJS) $(CLIENT_COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + TARG_OBJS += $(CHATD_MAINOBJ) $(CLIENT_MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + TARG_BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + TARG_BIN = ..\\..\\libapps$(LIBEXT) +else + TARG_BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean preconfig + +$(CHATD_COBJS) $(CHATD_MAINOBJ) $(CLIENT_COBJS) $(CLIENT_MAINOBJ) : %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(TARG_OBJS) + $(call ARCHIVE, $(TARG_BIN), $(TARG_OBJS)) + $(Q) touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) +ifeq ($(CONFIG_SYSTEM_TELNET_CHATD),y) + +$(BIN_DIR)$(DELIM)$(CHATD_PROGNAME): $(OBJS) $(CHATD_MAINOBJ) + @echo "LD: $(CHATD_PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(CHATD_PROGNAME) $(ARCHCRT0OBJ) $(CHATD_MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(CHATD_PROGNAME) + +chatd_install: $(BIN_DIR)$(DELIM)$(CHATD_PROGNAME) +else +chatd_install: +endif + +ifeq ($(CONFIG_SYSTEM_TELNET_CLIENT),y) + +$(BIN_DIR)$(DELIM)$(CLIENT_PROGNAME): $(OBJS) $(CLIENT_MAINOBJ) + @echo "LD: $(CLIENT_PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(CLIENT_PROGNAME) $(ARCHCRT0OBJ) $(CLIENT_MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(CLIENT_PROGNAME) + +client_install: $(BIN_DIR)$(DELIM)$(CLIENT_PROGNAME) +else +client_install: +endif + +install: chatd_install client_install + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +ifeq ($(CONFIG_SYSTEM_TELNET_CHATD),y) + +$(BUILTIN_REGISTRY)$(DELIM)$(CHATD_APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(CHATD_APPNAME),$(CHATD_PRIORITY),$(CHATD_STACKSIZE),$(CHATD_MAINNAME)) + +chatd_register: $(BUILTIN_REGISTRY)$(DELIM)$(CHATD_APPNAME)_main.bdat +else +chatd_register: +endif + +ifeq ($(CONFIG_SYSTEM_TELNET_CLIENT),y) +$(BUILTIN_REGISTRY)$(DELIM)$(CLIENT_APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(CLIENT_APPNAME),$(CLIENT_PRIORITY),$(CLIENT_STACKSIZE),$(CLIENT_MAINNAME)) + +client_register: $(BUILTIN_REGISTRY)$(DELIM)$(CLIENT_APPNAME)_main.bdat +else +client_register: +endif + +context: chatd_register client_register +else +context: +endif + +.depend: Makefile $(TARG_CSRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(TARG_CSRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call DELFILE, *.dSYM) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +preconfig: + +-include Make.dep diff --git a/system/telnet/telnet_chatd.c b/system/telnet/telnet_chatd.c new file mode 100644 index 000000000..e7a560b87 --- /dev/null +++ b/system/telnet/telnet_chatd.c @@ -0,0 +1,510 @@ +/**************************************************************************** + * apps/system/telnet/telnet_chatd.c + * + * Leveraged from libtelnet, https://github.com/seanmiddleditch/libtelnet. + * Modified and re-released under the BSD license: + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * The original authors of libtelnet are listed below. Per their licesne, + * "The author or authors of this code dedicate any and all copyright + * interest in this code to the public domain. We make this dedication for + * the benefit of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * code under copyright law." + * + * Author: Sean Middleditch + * (Also listed in the AUTHORS file are Jack Kelly + * and Katherine Flavel ) + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "netutils/telnetc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAX_USERS 64 +#define LINEBUFFER_SIZE 256 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct user_s +{ + char *name; + int sock; + struct telnet_s *telnet; + char linebuf[256]; + int linepos; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct telnet_telopt_s g_telopts[] = +{ + { + TELNET_TELOPT_COMPRESS2, TELNET_WILL, TELNET_DONT + }, + { + -1, 0, 0 + } +}; + +static struct user_s g_users[MAX_USERS]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void linebuffer_push(char *buffer, size_t size, int *linepos, + char ch, void (*cb) (const char *line, int overflow, + void *ud), void *ud) +{ + /* CRLF -- line terminator */ + + if (ch == '\n' && *linepos > 0 && buffer[*linepos - 1] == '\r') + { + /* NUL terminate (replaces \r in buffer), notify app, clear */ + + buffer[*linepos - 1] = 0; + cb(buffer, 0, ud); + *linepos = 0; + + /* CRNUL -- just a CR */ + } + else if (ch == 0 && *linepos > 0 && buffer[*linepos - 1] == '\r') + { + /* So nothing, the CR is already in the buffer */ + + /* Anything else (including technically invalid CR followed by anything + * besides LF or NUL -- just buffer if we have room \r + */ + } + else if (*linepos != size) + { + buffer[(*linepos)++] = ch; + + /* Buffer overflow */ + } + else + { + /* Terminate (NOTE: eats a byte), notify app, clear buffer */ + + buffer[size - 1] = 0; + cb(buffer, size - 1, ud); + *linepos = 0; + } +} + +static void _message(const char *from, const char *msg) +{ + int i; + + for (i = 0; i != MAX_USERS; ++i) + { + if (g_users[i].sock != -1) + { + telnet_printf(g_users[i].telnet, "%s: %s\n", from, msg); + } + } +} + +static void _send(int sock, const char *buffer, unsigned int size) +{ + int ret; + + /* Ignore on invalid socket */ + + if (sock == -1) + { + return; + } + + /* Send data */ + + while (size > 0) + { + if ((ret = send(sock, buffer, size, 0)) == -1) + { + if (errno != EINTR && errno != ECONNRESET) + { + fprintf(stderr, "send() failed: %d\n", errno); + exit(1); + } + else + { + return; + } + } + else if (ret == 0) + { + fprintf(stderr, "send() unexpectedly returned 0\n"); + exit(1); + } + + /* Update pointer and size to see if we've got more to send */ + + buffer += ret; + size -= ret; + } +} + +/* Process input line */ + +static void _online(const char *line, int overflow, void *ud) +{ + struct user_s *user = (struct user_s *)ud; + int i; + + /* If the user has no name, this is his "login" */ + + if (user->name == 0) + { + /* Must not be empty, must be at least 32 chars */ + + if (strlen(line) == 0 || strlen(line) > 32) + { + telnet_printf(user->telnet, "Invalid name.\nEnter name: "); + return; + } + + /* Must not already be in use */ + + for (i = 0; i != MAX_USERS; ++i) + { + if (g_users[i].name != 0 && strcmp(g_users[i].name, line) == 0) + { + telnet_printf(user->telnet, "Name in use.\nEnter name: "); + return; + } + } + + /* Keep name */ + + user->name = strdup(line); + telnet_printf(user->telnet, "Welcome, %s!\n", line); + return; + } + + /* If line is "quit" then, well, quit */ + + if (strcmp(line, "quit") == 0) + { + close(user->sock); + user->sock = -1; + _message(user->name, "** HAS QUIT **"); + free(user->name); + user->name = 0; + return; + } + + /* Just a message -- send to all users */ + + _message(user->name, line); +} + +static void _input(struct user_s *user, const char *buffer, unsigned int size) +{ + unsigned int i; + + for (i = 0; i != size; ++i) + { + linebuffer_push(user->linebuf, sizeof(user->linebuf), &user->linepos, + (char)buffer[i], _online, user); + } +} + +static void _event_handler(struct telnet_s *telnet, + union telnet_event_u *ev, void *user_data) +{ + struct user_s *user = (struct user_s *)user_data; + + switch (ev->type) + { + /* Data received */ + + case TELNET_EV_DATA: + _input(user, ev->data.buffer, ev->data.size); + telnet_negotiate(telnet, TELNET_WONT, TELNET_TELOPT_ECHO); + telnet_negotiate(telnet, TELNET_WILL, TELNET_TELOPT_ECHO); + break; + + /* Data must be sent */ + + case TELNET_EV_SEND: + _send(user->sock, ev->data.buffer, ev->data.size); + break; + + /* Enable compress2 if accepted by client */ + + case TELNET_EV_DO: + if (ev->neg.telopt == TELNET_TELOPT_COMPRESS2) + { + telnet_begin_compress2(telnet); + } + break; + + /* Error */ + + case TELNET_EV_ERROR: + close(user->sock); + user->sock = -1; + if (user->name != 0) + { + _message(user->name, "** HAS HAD AN ERROR **"); + free(user->name); + user->name = 0; + } + + telnet_free(user->telnet); + break; + + default: + /* Ignore */ + + break; + } +} + +int main(int argc, char **argv) +{ + char buffer[512]; + short listen_port; + int listen_sock; + int ret; + int i; + struct sockaddr_in addr; + socklen_t addrlen; + struct pollfd pfd[MAX_USERS + 1]; + + /* Check usage */ + + if (argc != 2) + { + fprintf(stderr, "Usage:\n %s \n", argv[0]); + return 1; + } + + /* Initialize data structures */ + + memset(&pfd, 0, sizeof(pfd)); + memset(g_users, 0, sizeof(g_users)); + + for (i = 0; i != MAX_USERS; ++i) + { + g_users[i].sock = -1; + } + + /* Parse listening port */ + + listen_port = (short)strtol(argv[1], 0, 10); + + /* Create listening socket */ + + if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + fprintf(stderr, "socket() failed: %d\n", errno); + return 1; + } + + /* Reuse address option */ + + ret = 1; + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&ret, sizeof(ret)); + + /* Bind to listening addr/port */ + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(listen_port); + if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) + { + fprintf(stderr, "bind() failed: %d\n", errno); + return 1; + } + + /* Listen for clients */ + + if (listen(listen_sock, 5) == -1) + { + fprintf(stderr, "listen() failed: %d\n", errno); + return 1; + } + + printf("LISTENING ON PORT %d\n", listen_port); + + /* Initialize listening descriptors */ + + pfd[MAX_USERS].fd = listen_sock; + pfd[MAX_USERS].events = POLLIN; + + /* Loop for ever */ + + for (;;) + { + /* Prepare for poll */ + + for (i = 0; i != MAX_USERS; ++i) + { + if (g_users[i].sock != -1) + { + pfd[i].fd = g_users[i].sock; + pfd[i].events = POLLIN; + } + else + { + pfd[i].fd = -1; + pfd[i].events = 0; + } + } + + /* Poll */ + + ret = poll(pfd, MAX_USERS + 1, -1); + if (ret == -1 && errno != EINTR) + { + fprintf(stderr, "poll() failed: %d\n", errno); + return 1; + } + + /* New connection */ + + if (pfd[MAX_USERS].revents & POLLIN) + { + /* Accept the sock */ + + addrlen = sizeof(addr); + if ((ret = accept(listen_sock, (struct sockaddr *)&addr, + &addrlen)) == -1) + { + fprintf(stderr, "accept() failed: %d\n", errno); + return 1; + } + + printf("Connection received.\n"); + + /* Find a free user */ + + for (i = 0; i != MAX_USERS; ++i) + { + if (g_users[i].sock == -1) + { + break; + } + } + + if (i == MAX_USERS) + { + printf(" rejected (too many users)\n"); + _send(ret, "Too many users.\r\n", 14); + close(ret); + } + + /* Init, welcome */ + + g_users[i].sock = ret; + g_users[i].telnet = telnet_init(g_telopts, _event_handler, 0, &g_users[i]); + telnet_negotiate(g_users[i].telnet, TELNET_WILL, + TELNET_TELOPT_COMPRESS2); + telnet_printf(g_users[i].telnet, "Enter name: "); + + telnet_negotiate(g_users[i].telnet, TELNET_WILL, TELNET_TELOPT_ECHO); + } + + /* Read from client */ + + for (i = 0; i != MAX_USERS; ++i) + { + /* Skip users that aren't actually connected */ + + if (g_users[i].sock == -1) + { + continue; + } + + if (pfd[i].revents & POLLIN) + { + if ((ret = recv(g_users[i].sock, buffer, sizeof(buffer), 0)) > 0) + { + telnet_recv(g_users[i].telnet, buffer, ret); + } + else if (ret == 0) + { + printf("Connection closed.\n"); + close(g_users[i].sock); + if (g_users[i].name != 0) + { + _message(g_users[i].name, "** HAS DISCONNECTED **"); + free(g_users[i].name); + g_users[i].name = 0; + } + + telnet_free(g_users[i].telnet); + g_users[i].sock = -1; + break; + } + else if (errno != EINTR) + { + fprintf(stderr, "recv(client) failed: %d\n", errno); + exit(1); + } + } + } + } + + /* Not that we can reach this, but GCC will cry if it's not here */ + + return 0; +} diff --git a/system/telnet/telnet_client.c b/system/telnet/telnet_client.c new file mode 100644 index 000000000..3e469fc25 --- /dev/null +++ b/system/telnet/telnet_client.c @@ -0,0 +1,425 @@ +/**************************************************************************** + * apps/system/telnet/telnet_client.c + * + * Leveraged from libtelnet, https://github.com/seanmiddleditch/libtelnet. + * Modified and re-released under the BSD license: + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * The original authors of libtelnet are listed below. Per their licesne, + * "The author or authors of this code dedicate any and all copyright + * interest in this code to the public domain. We make this dedication for + * the benefit of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * code under copyright law." + * + * Author: Sean Middleditch + * (Also listed in the AUTHORS file are Jack Kelly + * and Katherine Flavel ) + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_ZLIB +# include "zlib.h" +#endif + +#include "system/readline.h" +#include "netutils/telnetc.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct telnet_s *g_telnet; +static int g_echo; + +static const struct telnet_telopt_s g_telopts[] = +{ + { + TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO + }, + { + TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT + }, + { + TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO + }, + { + TELNET_TELOPT_MSSP, TELNET_WONT, TELNET_DO + }, + { + -1, 0, 0 + } +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void send_local_input(char *buffer, int size) +{ + static char crlf[] = { '\r', '\n' }; + int i; + + for (i = 0; i != size; ++i) + { + /* If we got a CR or LF, replace with CRLF NOTE that usually you'd get a + * CR in UNIX, but in raw mode we get LF instead (not sure why). + */ + + if (buffer[i] == '\r' || buffer[i] == '\n') + { + if (g_echo) + { + printf("\r\n"); + } + + telnet_send(g_telnet, crlf, 2); + } + else + { + if (g_echo) + { + putchar(buffer[i]); + } + + telnet_send(g_telnet, buffer + i, 1); + } + } + + fflush(stdout); +} + +static void telnet_ev_send(int sock, const char *buffer, size_t size) +{ + int ret; + + /* Send data */ + + while (size > 0) + { + if ((ret = send(sock, buffer, size, 0)) == -1) + { + fprintf(stderr, "send() failed: %d\n", errno); + exit(1); + } + else if (ret == 0) + { + fprintf(stderr, "send() unexpectedly returned 0\n"); + exit(1); + } + + /* Update pointer and size to see if we've got more to send */ + + buffer += ret; + size -= ret; + } +} + +static void _event_handler(struct telnet_s *telnet, + union telnet_event_u *ev, void *user_data) +{ + int sock = *(int *)user_data; + + switch (ev->type) + { + /* Data received */ + + case TELNET_EV_DATA: + printf("%.*s", (int)ev->data.size, ev->data.buffer); + fflush(stdout); + break; + + /* Data must be sent */ + + case TELNET_EV_SEND: + telnet_ev_send(sock, ev->data.buffer, ev->data.size); + break; + + /* Request to enable remote feature (or receipt) */ + + case TELNET_EV_WILL: + /* We'll agree to turn off our echo if server wants us to stop */ + + if (ev->neg.telopt == TELNET_TELOPT_ECHO) + { + g_echo = 0; + } + + break; + + /* Notification of disabling remote feature (or receipt) */ + + case TELNET_EV_WONT: + if (ev->neg.telopt == TELNET_TELOPT_ECHO) + { + g_echo = 1; + } + break; + + /* Request to enable local feature (or receipt) */ + + case TELNET_EV_DO: + break; + + /* Demand to disable local feature (or receipt) */ + + case TELNET_EV_DONT: + break; + + /* Respond to TTYPE commands */ + + case TELNET_EV_TTYPE: + /* Respond with our terminal type, if requested */ + + if (ev->ttype.cmd == TELNET_TTYPE_SEND) + { + telnet_ttype_is(telnet, getenv("TERM")); + } + break; + + /* Respond to particular subnegotiations */ + + case TELNET_EV_SUBNEGOTIATION: + break; + + /* Error */ + + case TELNET_EV_ERROR: + fprintf(stderr, "ERROR: %s\n", ev->error.msg); + exit(1); + + default: + /* Ignore */ + + break; + } +} + +static void show_usage(const char *progname, int exitcode) +{ + fprintf(stderr, "Usage:\n %s \n", progname); + exit(exitcode) ; +} + +int main(int argc, char **argv) +{ + char buffer[512]; + union + { + struct sockaddr generic; +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 ipv6; +#endif +#ifdef CONFIG_NET_IPv4 + struct sockaddr_in ipv4; +#endif + } server; + union + { +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 ipv6; +#endif +#ifdef CONFIG_NET_IPv4 + struct sockaddr_in ipv4; +#endif + } local; + struct pollfd pfd[2]; + sa_family_t family; + uint16_t addrlen; + int portno; + int sock; + int ret; + + /* Check usage */ + + if (argc != 3) + { + fprintf(stderr, "Invalid number of arguments\n"); + show_usage(argv[0], 1); + } + + /* Convert the port number to binary */ + + portno = atoi(argv[2]); + if (portno < 0 || portno > UINT16_MAX) + { + fprintf(stderr, "Invalid port number\n"); + show_usage(argv[0], 1); + } + + /* Convert the argument into a binary address */ + + memset(&local, 0, sizeof(local)); + +#ifdef CONFIG_EXAMPLES_NETTEST_IPv6 + addrlen = sizeof(struct sockaddr_in6); + family = AF_INET6; + + local.ipv6.sin6_family = AF_INET6; + server.ipv6.sin6_family = AF_INET6; + server.ipv6.sin6_port = htons(portno); + + ret = inet_pton(AF_INET6, argv[1], server.ipv6.sin6_addr.s6_addr); + if (ret < 0) +#endif +#ifdef CONFIG_EXAMPLES_NETTEST_IPv + { + addrlen = sizeof(struct sockaddr_in); + family = AF_INET; + + local.ipv4.sin_family = AF_INET; + server.ipv4.sin_family = AF_INET; + server.ipv4.sin_port = htons(portno); + + ret = inet_pton(AF_INET, argv[1], &server.ipv4.sin_addr); + } + + if (ret < 0) +#endif + { + fprintf(stderr, "ERROR: is invalid\n"); + show_usage(argv[0], 1); + } + + /* Create server socket */ + + sock = socket(family, SOCK_STREAM, 0); + if (sock < 0) + { + fprintf(stderr, "socket() failed: %d\n", errno); + return 1; + } + + /* Bind server socket */ + + ret = bind(sock, (struct sockaddr *)&local, addrlen); + if (ret < 0) + { + fprintf(stderr, "bind() failed: %d\n", errno); + return 1; + } + + /* Connect */ + + ret = connect(sock, &server.generic, addrlen); + if (ret < 0) + { + fprintf(stderr, "connect() failed: %d\n", errno); + return 1; + } + + /* Set input echoing on by default */ + + g_echo = 1; + + /* Initialize telnet box */ + + g_telnet = telnet_init(g_telopts, _event_handler, 0, &sock); + + /* Initialize poll descriptors */ + + memset(pfd, 0, sizeof(pfd)); + pfd[0].fd = 1; + pfd[0].events = POLLIN; + pfd[1].fd = sock; + pfd[1].events = POLLIN; + + /* Loop while both connections are open */ + + while (poll(pfd, 2, -1) != -1) + { + /* Read from stdin */ + + if (pfd[0].revents & POLLIN) + { + ret = std_readline(buffer, sizeof(buffer)); + if (ret > 0) + { + send_local_input(buffer, ret); + } + else if (ret == 0) + { + break; + } + else + { + fprintf(stderr, "recv(server) failed: %d\n", errno); + exit(1); + } + } + + /* Read from client */ + + if (pfd[1].revents & POLLIN) + { + if ((ret = recv(sock, buffer, sizeof(buffer), 0)) > 0) + { + telnet_recv(g_telnet, buffer, ret); + } + else if (ret == 0) + { + break; + } + else + { + fprintf(stderr, "recv(client) failed: %d\n", errno); + exit(1); + } + } + } + + /* Clean up */ + + telnet_free(g_telnet); + close(sock); + return 0; +}