From 426dc74b959df16ea2c63ddefb07aa874a17a367 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 2 Feb 2012 16:04:09 +0000 Subject: NSH now uses the new Telnet daemon and built-in tasks started by NSH can be used over Telnet git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4361 42af7a65-404d-4744-a932-0658087f49c3 --- apps/nshlib/nsh_telnetd.c | 833 +++++----------------------------------------- 1 file changed, 83 insertions(+), 750 deletions(-) (limited to 'apps/nshlib/nsh_telnetd.c') diff --git a/apps/nshlib/nsh_telnetd.c b/apps/nshlib/nsh_telnetd.c index 0670c9a05..66923deb2 100644 --- a/apps/nshlib/nsh_telnetd.c +++ b/apps/nshlib/nsh_telnetd.c @@ -1,14 +1,8 @@ /**************************************************************************** * apps/nshlib/nsh_telnetd.c * - * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * This is a leverage of similar logic from uIP: - * - * Author: Adam Dunkels - * Copyright (c) 2003, Adam Dunkels. - * All rights reserved. + * Copyright (C) 2007-2012 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 @@ -17,23 +11,26 @@ * 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. + * ****************************************************************************/ /**************************************************************************** @@ -42,812 +39,148 @@ #include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#if defined(CONFIG_NSH_DHCPC) -# include -# include -#endif +#include #include "nsh.h" +#include "nsh_console.h" #ifdef CONFIG_NSH_TELNET /**************************************************************************** - * Definitions + * Pre-processor 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 - -#ifdef CONFIG_NSH_TELNETD_DUMPBUFFER -# define nsh_telnetdump(vtbl,msg,buf,nb) nsh_dumpbuffer(vtbl,msg,buf,nb) -#else -# define nsh_telnetdump(vtbl,msg,buf,nb) -#endif - /**************************************************************************** * Private Types ****************************************************************************/ -struct telnetio_s -{ - sem_t tio_sem; - int tio_sockfd; - uint8_t tio_bufndx; - uint8_t tio_state; - char tio_inbuffer[CONFIG_NSH_IOBUFFER_SIZE]; -}; - -struct redirect_s -{ - int rd_fd; /* Re-direct file descriptor */ - FILE *rd_stream; /* Re-direct stream */ -}; - -struct telnetsave_s -{ - bool ts_redirected; - union - { - struct telnetio_s *tn; - struct redirect_s rd; - } u; -}; - -struct telnetd_s -{ - struct nsh_vtbl_s tn_vtbl; - uint16_t tn_sndlen; - bool tn_redirected; - union - { - struct telnetio_s *tn; - struct redirect_s rd; - } u; - char tn_outbuffer[CONFIG_NSH_IOBUFFER_SIZE]; - char tn_cmd[CONFIG_NSH_LINELEN]; -}; - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -#ifndef CONFIG_NSH_DISABLEBG -static void tio_semtake(struct telnetio_s *tio); -static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl); -#endif -static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl); -static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes); -static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); -static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); -static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl); -static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); -static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); -static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl); - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** - * Name: tio_semtake + * Private Data ****************************************************************************/ -static void tio_semtake(struct telnetio_s *tio) -{ - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&tio->tio_sem) != 0) - { - /* The only case that an error should occur here is if the wait was - * awakened by a signal. - */ - - ASSERT(errno == EINTR); - } -} - /**************************************************************************** - * Name: tio_semgive + * Public Data ****************************************************************************/ -#define tio_semgive(tio) ASSERT(sem_post(&tio->tio_sem) == 0) - /**************************************************************************** - * Name: nsh_allocstruct - ****************************************************************************/ - -static FAR struct telnetd_s *nsh_allocstruct(void) -{ - struct telnetd_s *pstate = (struct telnetd_s *)zalloc(sizeof(struct telnetd_s)); - if (pstate) - { -#ifndef CONFIG_NSH_DISABLEBG - pstate->tn_vtbl.clone = nsh_telnetclone; - pstate->tn_vtbl.release = nsh_telnetrelease; -#endif - pstate->tn_vtbl.write = nsh_telnetwrite; - pstate->tn_vtbl.output = nsh_telnetoutput; - pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer; - pstate->tn_vtbl.redirect = nsh_telnetredirect; - pstate->tn_vtbl.undirect = nsh_telnetundirect; - pstate->tn_vtbl.exit = nsh_telnetexit; - } - return pstate; -} - -/**************************************************************************** - * Name: nsh_openifnotopen + * Private Functions ****************************************************************************/ -static int nsh_openifnotopen(struct telnetd_s *pstate) -{ - struct redirect_s *rd = &pstate->u.rd; - - /* The stream is open in a lazy fashion. This is done because the file - * descriptor may be opened on a different task than the stream. - */ - - if (!rd->rd_stream) - { - rd->rd_stream = fdopen(rd->rd_fd, "w"); - if (!rd->rd_stream) - { - return ERROR; - } - } - return 0; -} - /**************************************************************************** - * Name: nsh_closeifnotclosed + * Public Functions ****************************************************************************/ -static void nsh_closeifnotclosed(struct telnetd_s *pstate) -{ - struct redirect_s *rd = &pstate->u.rd; - - if (rd->rd_stream == stdout) - { - fflush(stdout); - rd->rd_fd = 1; - } - else - { - if (rd->rd_stream) - { - fflush(rd->rd_stream); - fclose(rd->rd_stream); - } - else if (rd->rd_fd >= 0 && rd->rd_fd != 1) - { - close(rd->rd_fd); - } - - rd->rd_fd = -1; - rd->rd_stream = NULL; - } -} - /**************************************************************************** - * Name: nsh_putchar - * - * Description: - * Add another parsed character to the TELNET command string - * - * Assumption: - * Caller holds TIO semaphore - * + * Name: nsh_telnetmain ****************************************************************************/ -static void nsh_putchar(struct telnetd_s *pstate, uint8_t ch) +int nsh_telnetmain(int argc, char *argv[]) { - struct telnetio_s *tio = pstate->u.tn; - - /* Ignore carriage returns */ + FAR struct console_stdio_s *pstate = nsh_newconsole(); + DEBUGASSERT(pstate != NULL); - if (ch == ISO_cr) - { - return; - } + dbg("Session [%d] Started\n", getpid()); - /* Add all other characters to the cmd buffer */ + /* Present a greeting */ - pstate->tn_cmd[tio->tio_bufndx] = ch; + fputs(g_nshgreeting, pstate->cn_outstream); + fflush(pstate->cn_outstream); - /* If a newline was added or if the buffer is full, then process it now */ + /* Execute the startup script */ - if (ch == ISO_nl || tio->tio_bufndx == (CONFIG_NSH_LINELEN - 1)) - { - pstate->tn_cmd[tio->tio_bufndx] = '\0'; - nsh_telnetdump(&pstate->tn_vtbl, "TELNET CMD", - (uint8_t*)pstate->tn_cmd, strlen(pstate->tn_cmd)); - nsh_parse(&pstate->tn_vtbl, pstate->tn_cmd); - tio->tio_bufndx = 0; - } - else - { - tio->tio_bufndx++; - vdbg("Add '%c', bufndx=%d\n", ch, tio->tio_bufndx); - } -} +#if defined(CONFIG_NSH_ROMFSETC) && !defined(CONFIG_NSH_CONSOLE) + (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH); +#endif -/**************************************************************************** - * Name: nsh_sendopt - * - * Description: - * - ****************************************************************************/ + /* Then enter the command line parsing loop */ -static void nsh_sendopt(struct telnetd_s *pstate, uint8_t option, uint8_t value) -{ - struct telnetio_s *tio = pstate->u.tn; - uint8_t optbuf[4]; - optbuf[0] = TELNET_IAC; - optbuf[1] = option; - optbuf[2] = value; - optbuf[3] = 0; - - nsh_telnetdump(&pstate->tn_vtbl, "Send optbuf", optbuf, 4); - tio_semtake(tio); /* Only one call to send at a time */ - if (send(tio->tio_sockfd, optbuf, 4, 0) < 0) + for (;;) { - dbg("[%d] Failed to send TELNET_IAC: %d\n", tio->tio_sockfd, errno); - } - tio_semgive(tio); -} + /* Display the prompt string */ -/**************************************************************************** - * Name: nsh_flush - * - * Description: - * Dump the buffered output info. - * - ****************************************************************************/ + fputs(g_nshprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); -static void nsh_flush(FAR struct telnetd_s *pstate) -{ - struct telnetio_s *tio = pstate->u.tn; + /* Get the next line of input from the Telnet client */ - if (pstate->tn_sndlen > 0) - { - nsh_telnetdump(&pstate->tn_vtbl, "Shell output", - (uint8_t*)pstate->tn_outbuffer, pstate->tn_sndlen); - tio_semtake(tio); /* Only one call to send at a time */ - if (send(tio->tio_sockfd, pstate->tn_outbuffer, pstate->tn_sndlen, 0) < 0) + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) { - dbg("[%d] Failed to send response: %d\n", tio->tio_sockfd, errno); - } - tio_semgive(tio); - } - pstate->tn_sndlen = 0; -} + /* Parse process the received Telnet command */ -/**************************************************************************** - * Name: nsh_receive - * - * Description: - * Process a received TELENET buffer - * - ****************************************************************************/ - -static int nsh_receive(struct telnetd_s *pstate, size_t len) -{ - struct telnetio_s *tio = pstate->u.tn; - char *ptr = tio->tio_inbuffer; - uint8_t ch; - - while (len > 0) - { - ch = *ptr++; - len--; - - vdbg("ch=%02x state=%d\n", ch, tio->tio_state); - switch (tio->tio_state) - { - case STATE_IAC: - if (ch == TELNET_IAC) - { - nsh_putchar(pstate, ch); - tio->tio_state = STATE_NORMAL; - } - else - { - switch (ch) - { - case TELNET_WILL: - tio->tio_state = STATE_WILL; - break; - - case TELNET_WONT: - tio->tio_state = STATE_WONT; - break; - - case TELNET_DO: - tio->tio_state = STATE_DO; - break; - - case TELNET_DONT: - tio->tio_state = STATE_DONT; - break; - - default: - tio->tio_state = STATE_NORMAL; - break; - } - } - break; - - case STATE_WILL: - /* Reply with a DONT */ - - nsh_sendopt(pstate, TELNET_DONT, ch); - tio->tio_state = STATE_NORMAL; - break; - - case STATE_WONT: - /* Reply with a DONT */ - - nsh_sendopt(pstate, TELNET_DONT, ch); - tio->tio_state = STATE_NORMAL; - break; - - case STATE_DO: - /* Reply with a WONT */ - - nsh_sendopt(pstate, TELNET_WONT, ch); - tio->tio_state = STATE_NORMAL; - break; - - case STATE_DONT: - /* Reply with a WONT */ - - nsh_sendopt(pstate, TELNET_WONT, ch); - tio->tio_state = STATE_NORMAL; - break; - - case STATE_NORMAL: - if (ch == TELNET_IAC) - { - tio->tio_state = STATE_IAC; - } - else - { - nsh_putchar(pstate, ch); - } - break; + (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line); + fflush(pstate->cn_outstream); } - } - return OK; -} - -/**************************************************************************** - * Name: nsh_connection - * - * 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 *nsh_connection(void *arg) -{ - struct telnetd_s *pstate = nsh_allocstruct(); - struct telnetio_s *tio = (struct telnetio_s *)zalloc(sizeof(struct telnetio_s)); - struct nsh_vtbl_s *vtbl = &pstate->tn_vtbl; - int sockfd = (int)arg; - int ret = ERROR; - - dbg("[%d] Started\n", sockfd); - - /* Verify that the state structure was successfully allocated */ - - if (pstate && tio) - { - /* Initialize the thread state structure */ - - sem_init(&tio->tio_sem, 0, 1); - tio->tio_sockfd = sockfd; - tio->tio_state = STATE_NORMAL; - pstate->u.tn = tio; - - /* Output a greeting */ - - nsh_output(vtbl, g_nshgreeting); - - /* Execute the startup script */ - -#if defined(CONFIG_NSH_ROMFSETC) && !defined(CONFIG_NSH_CONSOLE) - (void)nsh_script(vtbl, "init", NSH_INITPATH); -#endif - - /* Loop processing each TELNET command */ - - do + else { - /* Display the prompt string */ - - nsh_output(vtbl, g_nshprompt); - nsh_flush(pstate); - - /* Read a buffer of data from the TELNET client */ - - ret = recv(tio->tio_sockfd, tio->tio_inbuffer, - CONFIG_NSH_IOBUFFER_SIZE, 0); - if (ret > 0) - { - - /* Process the received TELNET data */ - - nsh_telnetdump(vtbl, "Received buffer", - (uint8_t*)tio->tio_inbuffer, ret); - ret = nsh_receive(pstate, ret); - } + fprintf(pstate->cn_outstream, g_fmtcmdfailed, "fgets", NSH_ERRNO); + nsh_exit(&pstate->cn_vtbl, 1); } - while (ret >= 0 && tio->tio_state != STATE_CLOSE); - dbg("[%d] ret=%d tn.tio_state=%d\n", sockfd, ret, tio->tio_state); - - /* End of command processing -- Clean up and exit */ } - /* Exit the task */ + /* Clean up */ - if (pstate) - { - free(pstate); - } + nsh_exit(&pstate->cn_vtbl, 0); - if (tio) - { - sem_destroy(&tio->tio_sem); - free(tio); - } + /* We do not get here, but this is necessary to keep some compilers happy */ - dbg("[%d] Exitting\n", sockfd); - close(sockfd); - return NULL; + return OK; } /**************************************************************************** - * Name: nsh_telnetwrite - * - * Description: - * write a buffer to the remote shell window. - * - * Currently only used by cat. - * + * Public Functions ****************************************************************************/ -static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes) -{ - struct telnetd_s *pstate = (struct telnetd_s *)vtbl; - struct telnetio_s *tio = pstate->u.tn; - ssize_t ret = nbytes; - - /* Flush anything already in the output buffer */ - - nsh_flush(pstate); - - /* Then write the user buffer */ - - nsh_telnetdump(&pstate->tn_vtbl, "Buffer output",(uint8_t*)buffer, nbytes); - - tio_semtake(tio); /* Only one call to send at a time */ - ret = send(tio->tio_sockfd, buffer, nbytes, 0); - if (ret < 0) - { - dbg("[%d] Failed to send buffer: %d\n", tio->tio_sockfd, errno); - } - - tio_semgive(tio); - return ret; -} - /**************************************************************************** - * Name: nsh_telnetoutput + * Name: nsh_telnetstart * * Description: - * Print a string to the remote shell window. + * nsh_telnetstart() starts the Telnet daemon that will allow multiple + * NSH connections via Telnet. This function returns immediately after + * the daemon has been started. * - * 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. + * Input Parameters: + * None. All of the properties of the Telnet daemon are controlled by + * NuttX configuration setting. * + * Returned Values: + * Zero if the Telnet daemon was successfully started. A negated errno + * value will be returned on failure. + * ****************************************************************************/ -static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) +int nsh_telnetstart(void) { - struct telnetd_s *pstate = (struct telnetd_s *)vtbl; - int nbytes = pstate->tn_sndlen; - int len; - va_list ap; + struct telnetd_config_s config; + int ret; - /* Put the new info into the buffer. Here we are counting on the fact that - * no output strings will exceed CONFIG_NSH_LINELEN! - */ + /* Configure the telnet daemon */ - va_start(ap, fmt); - vsnprintf(&pstate->tn_outbuffer[nbytes], - (CONFIG_NSH_IOBUFFER_SIZE - 1) - nbytes, fmt, ap); - va_end(ap); + config.d_port = HTONS(CONFIG_NSH_TELNETD_PORT); + config.d_priority = CONFIG_NSH_TELNETD_DAEMONPRIO; + config.d_stacksize = CONFIG_NSH_TELNETD_DAEMONSTACKSIZE; + config.t_priority = CONFIG_NSH_TELNETD_CLIENTPRIO; + config.t_stacksize = CONFIG_NSH_TELNETD_CLIENTSTACKSIZE; + config.t_entry = nsh_telnetmain; - /* Get the size of the new string just added and the total size of - * buffered data - */ + /* Start the telnet daemon */ - len = strlen(&pstate->tn_outbuffer[nbytes]); - nbytes += len; - - /* Expand any terminating \n to \r\n */ - - if (nbytes < (CONFIG_NSH_IOBUFFER_SIZE - 2) && - pstate->tn_outbuffer[nbytes-1] == '\n') - { - pstate->tn_outbuffer[nbytes-1] = ISO_cr; - pstate->tn_outbuffer[nbytes] = ISO_nl; - pstate->tn_outbuffer[nbytes+1] = '\0'; - nbytes++; - } - pstate->tn_sndlen = nbytes; - - /* Flush to the network if the buffer does not have room for one more - * maximum length string. - */ - - if (nbytes > CONFIG_NSH_IOBUFFER_SIZE - CONFIG_NSH_LINELEN) + vdbg("Starting the Telnet daemon\n"); + ret = telnetd_start(&config); + if (ret < 0) { - nsh_flush(pstate); + dbg("Failed to tart the Telnet daemon: %d\n", ret); } - return len; -} - -/**************************************************************************** - * Name: nsh_redirectoutput - * - * Description: - * Print a string to the currently selected stream. - * - ****************************************************************************/ - -static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) -{ - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - va_list ap; - int ret; - - /* The stream is open in a lazy fashion. This is done because the file - * descriptor may be opened on a different task than the stream. The - * actual open will then occur with the first output from the new task. - */ - - if (nsh_openifnotopen(pstate) != 0) - { - return ERROR; - } - - va_start(ap, fmt); - ret = vfprintf(pstate->u.rd.rd_stream, fmt, ap); - va_end(ap); - return ret; } -/**************************************************************************** - * Name: nsh_telnetlinebuffer - * - * Description: - * Return a reference to the current line buffer - * -* ****************************************************************************/ - -static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl) -{ - struct telnetd_s *pstate = (struct telnetd_s *)vtbl; - return pstate->tn_cmd; -} - -/**************************************************************************** - * Name: nsh_telnetclone - * - * Description: - * Make an independent copy of the vtbl - * - ****************************************************************************/ - -#ifndef CONFIG_NSH_DISABLEBG -static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl) -{ - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - FAR struct telnetd_s *pclone = nsh_allocstruct(); - FAR struct nsh_vtbl_s *ret = NULL; - - if (pclone) - { - if (pstate->tn_redirected) - { - pclone->tn_redirected = true; - pclone->tn_vtbl.output = nsh_redirectoutput; - pclone->u.rd.rd_fd = pstate->u.rd.rd_fd; - pclone->u.rd.rd_stream = NULL; - } - else - { - pclone->u.tn = pstate->u.tn; - } - ret = &pclone->tn_vtbl; - } - return ret; -} -#endif - -/**************************************************************************** - * Name: nsh_telnetrelease - * - * Description: - * Release the cloned instance - * - ****************************************************************************/ - -#ifndef CONFIG_NSH_DISABLEBG -static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl) -{ - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - - if (pstate->tn_redirected) - { - nsh_closeifnotclosed(pstate); - } - else - { - nsh_flush(pstate); - } - free(pstate); -} -#endif - -/**************************************************************************** - * Name: nsh_telnetredirect - * - * Description: - * Set up for redirected output. This function is called from nsh_parse() - * in two different contexts: - * - * 1) Redirected background commands of the form: command > xyz.text & - * - * In this case: - * - vtbl: A newly allocated and initialized instance created by - * nsh_telnetclone, - * - fd:- The file descriptor of the redirected output - * - save: NULL - * - * nsh_telnetrelease() will perform the clean-up when the clone is - * destroyed. - * - * 2) Redirected foreground commands of the form: command > xyz.txt - * - * In this case: - * - vtbl: The current state structure, - * - fd: The file descriptor of the redirected output - * - save: Where to save the re-directed registers. - * - * nsh_telnetundirect() will perform the clean-up after the redirected - * command completes. - * - ****************************************************************************/ - -static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save) -{ - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - FAR struct telnetsave_s *ssave = (FAR struct telnetsave_s *)save; - - if (pstate->tn_redirected) - { - (void)nsh_openifnotopen(pstate); - fflush(pstate->u.rd.rd_stream); - if (!ssave) - { - fclose(pstate->u.rd.rd_stream); - } - } - - if (ssave) - { - ssave->ts_redirected = pstate->tn_redirected; - memcpy(&ssave->u.rd, &pstate->u.rd, sizeof(struct redirect_s)); - } - - pstate->tn_redirected = true; - pstate->u.rd.rd_fd = fd; - pstate->u.rd.rd_stream = NULL; -} - -/**************************************************************************** - * Name: nsh_telnetundirect - * - * Description: - * Set up for redirected output - * - ****************************************************************************/ - -static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save) -{ - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - FAR struct telnetsave_s *ssave = (FAR struct telnetsave_s *)save; - - if (pstate->tn_redirected) - { - nsh_closeifnotclosed(pstate); - } - - pstate->tn_redirected = ssave->ts_redirected; - memcpy(&pstate->u.rd, &ssave->u.rd, sizeof(struct redirect_s)); -} - -/**************************************************************************** - * Name: nsh_telnetexit - * - * Description: - * Quit the shell instance - * - ****************************************************************************/ - -static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl) -{ - struct telnetd_s *pstate = (struct telnetd_s *)vtbl; - pstate->u.tn->tio_state = STATE_CLOSE; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: nsh_telnetmain - * - * Description: - * This is the main processing thread for telnetd. It never returns - * unless an error occurs - * - ****************************************************************************/ - -int nsh_telnetmain(int argc, char *argv[]) -{ - /* Execute nsh_connection() on each connection to port 23 */ - - uip_server(HTONS(23), nsh_connection, CONFIG_NSH_STACKSIZE); - return OK; -} - #endif /* CONFIG_NSH_TELNET */ -- cgit v1.2.3