From 332a8cdade9fa5609a57b162d7a7e6d52ff91073 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 16 Aug 2008 20:52:06 +0000 Subject: Concurrent telnet+serial git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@824 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/examples/nsh/nsh.h | 13 +- nuttx/examples/nsh/nsh_main.c | 16 +- nuttx/examples/nsh/nsh_serial.c | 95 +++++---- nuttx/examples/nsh/nsh_telnetd.c | 421 +++++++++++++++++++++++++++++++-------- 4 files changed, 411 insertions(+), 134 deletions(-) (limited to 'nuttx/examples/nsh') diff --git a/nuttx/examples/nsh/nsh.h b/nuttx/examples/nsh/nsh.h index 77877908b..4855ea366 100644 --- a/nuttx/examples/nsh/nsh.h +++ b/nuttx/examples/nsh/nsh.h @@ -96,8 +96,9 @@ #define nsh_addref(v) (v)->addref(v) #define nsh_release(v) (v)->release(v) #define nsh_linebuffer(v) (v)->linebuffer(v) -#define nsh_redirect(v,f) (v)->redirect(v,f) -#define nsh_undirect(v,d) (v)->undirect(v,d) +#define nsh_redirect(v,f,s) (v)->redirect(v,f,s) +#define nsh_undirect(v,s) (v)->undirect(v,s) +#define nsh_exit(v) (v)->exit(v) #ifdef CONFIG_CPP_HAVE_VARARGS # define nsh_output(v, fmt...) (v)->output(v, ##fmt) @@ -105,6 +106,8 @@ # define nsh_output vtbl->output #endif +#define SAVE_SIZE (sizeof(int) + sizeof(FILE*) + sizeof(boolean)) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -116,8 +119,9 @@ struct nsh_vtbl_s void (*release)(FAR struct nsh_vtbl_s *vtbl); int (*output)(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl); - FAR void *(*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd); - void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR void *direct); + void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR ubyte *save); + void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR ubyte *save); + void (*exit)(FAR struct nsh_vtbl_s *vtbl); }; typedef void (*cmd_t)(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); @@ -158,7 +162,6 @@ extern int nsh_telnetmain(int argc, char *argv[]); extern void cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); extern void cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); -extern void cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); extern void cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); #if CONFIG_NFILE_DESCRIPTORS > 0 diff --git a/nuttx/examples/nsh/nsh_main.c b/nuttx/examples/nsh/nsh_main.c index c2754ae3f..d318802e1 100644 --- a/nuttx/examples/nsh/nsh_main.c +++ b/nuttx/examples/nsh/nsh_main.c @@ -73,6 +73,7 @@ struct cmdmap_s ****************************************************************************/ static void cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +static void cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); static void cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); /**************************************************************************** @@ -196,6 +197,15 @@ static void cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) nsh_output(vtbl, g_fmtcmdnotfound, argv[0]); } +/**************************************************************************** + * Name: cmd_exit + ****************************************************************************/ + +static void cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_exit(vtbl); +} + /**************************************************************************** * Name: nsh_execute ****************************************************************************/ @@ -596,7 +606,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) if (redirect) { - (void)nsh_redirect(bkgvtbl, fd); + (void)nsh_redirect(bkgvtbl, fd, NULL); } /* Get the execution priority of this task */ @@ -659,7 +669,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) } else { - void *save; + ubyte save[SAVE_SIZE]; /* Increment the reference count on the vtbl. This reference count will * be decremented at the end of nsh_execute() and exists only for compatibility @@ -677,7 +687,7 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) if (redirect) { - save = nsh_redirect(vtbl, fd); + nsh_redirect(vtbl, fd, save); } /* Then execute the command in "foreground" -- i.e., while the user waits diff --git a/nuttx/examples/nsh/nsh_serial.c b/nuttx/examples/nsh/nsh_serial.c index c9abc88ed..95953171c 100644 --- a/nuttx/examples/nsh/nsh_serial.c +++ b/nuttx/examples/nsh/nsh_serial.c @@ -58,13 +58,19 @@ struct serial_s { - struct nsh_vtbl_s vtbl; + struct nsh_vtbl_s ss_vtbl; int ss_refs; /* Reference counts on the instance */ int ss_fd; /* Re-direct file descriptor */ - FILE *ss_stream; /* Redirect file descriptor */ + FILE *ss_stream; /* Re-direct stream */ char ss_line[CONFIG_EXAMPLES_NSH_LINELEN]; }; +struct serialsave_s +{ + int ss_fd; /* Re-direct file descriptor */ + FILE *ss_stream; /* Re-direct stream */ +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -74,8 +80,9 @@ static void nsh_consoleaddref(FAR struct nsh_vtbl_s *vtbl); static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl); static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl); -static FAR void *nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd); -static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR void *direct); +static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR ubyte *save); +static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR ubyte *save); +static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl); /**************************************************************************** * Private Data @@ -98,17 +105,18 @@ static inline FAR struct serial_s *nsh_allocstruct(void) struct serial_s *pstate = (struct serial_s *)malloc(sizeof(struct serial_s)); if (pstate) { - pstate->vtbl.clone = nsh_consoleclone; - pstate->vtbl.addref = nsh_consoleaddref; - pstate->vtbl.release = nsh_consolerelease; - pstate->vtbl.output = nsh_consoleoutput; - pstate->vtbl.linebuffer = nsh_consolelinebuffer; - pstate->vtbl.redirect = nsh_consoleredirect; - pstate->vtbl.undirect = nsh_consoleundirect; - - pstate->ss_refs = 1; - pstate->ss_fd = 1; - pstate->ss_stream = stdout; + pstate->ss_vtbl.clone = nsh_consoleclone; + pstate->ss_vtbl.addref = nsh_consoleaddref; + pstate->ss_vtbl.release = nsh_consolerelease; + pstate->ss_vtbl.output = nsh_consoleoutput; + pstate->ss_vtbl.linebuffer = nsh_consolelinebuffer; + pstate->ss_vtbl.redirect = nsh_consoleredirect; + pstate->ss_vtbl.undirect = nsh_consoleundirect; + pstate->ss_vtbl.exit = nsh_consoleexit; + + pstate->ss_refs = 1; + pstate->ss_fd = 1; + pstate->ss_stream = stdout; } return pstate; } @@ -221,7 +229,7 @@ static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl) FAR struct serial_s *pclone = nsh_allocstruct(); pclone->ss_fd = pstate->ss_fd; pclone->ss_stream = NULL; - return &pclone->vtbl; + return &pclone->ss_vtbl; } /**************************************************************************** @@ -269,18 +277,25 @@ static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl) * ****************************************************************************/ -static FAR void *nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd) +static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR ubyte *save) { - FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; - void *ret; + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save; (void)nsh_openifnotopen(pstate); - ret = pstate->ss_stream; fflush(pstate->ss_stream); + if (ssave) + { + ssave->ss_fd = pstate->ss_fd; + ssave->ss_stream = pstate->ss_stream; + } + else + { + fclose(pstate->ss_stream); + } pstate->ss_fd = fd; - pstate->ss_stream = NULL; - return ret; + pstate->ss_stream = NULL; } /**************************************************************************** @@ -291,12 +306,27 @@ static FAR void *nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd) * ****************************************************************************/ -static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR void *direct) +static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR ubyte *save) { FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save; + nsh_closeifnotclosed(pstate); - pstate->ss_fd = -1; - pstate->ss_stream = (FILE*)direct; + pstate->ss_fd = ssave->ss_fd; + pstate->ss_stream = ssave->ss_stream; +} + +/**************************************************************************** + * Name: nsh_consoleexit + * + * Description: + * Exit the shell task + * + ****************************************************************************/ + +static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl) +{ + exit(0); } /**************************************************************************** @@ -327,21 +357,8 @@ int nsh_consolemain(int argc, char *argv[]) { /* Parse process the command */ - (void)nsh_parse(&pstate->vtbl, pstate->ss_line); + (void)nsh_parse(&pstate->ss_vtbl, pstate->ss_line); fflush(pstate->ss_stream); } } } - -/**************************************************************************** - * Name: cmd_exit - * - * Description: - * Exit the shell task - * - ****************************************************************************/ - -void cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) -{ - exit(0); -} diff --git a/nuttx/examples/nsh/nsh_telnetd.c b/nuttx/examples/nsh/nsh_telnetd.c index 551509d74..0e99dd36a 100644 --- a/nuttx/examples/nsh/nsh_telnetd.c +++ b/nuttx/examples/nsh/nsh_telnetd.c @@ -1,7 +1,7 @@ /**************************************************************************** * examples/nsh/nsh_telnetd.c * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This is a leverage of similar logic from uIP: @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -83,15 +84,42 @@ * Private Types ****************************************************************************/ +struct telnetio_s +{ + int tio_sockfd; + uint16 tio_sndlen; + uint8 tio_bufndx; + uint8 tio_state; + char tio_buffer[CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE]; +}; + +struct redirect_s +{ + int rd_fd; /* Re-direct file descriptor */ + FILE *rd_stream; /* Re-direct stream */ +}; + +struct telnetsave_s +{ + boolean ts_redirected; + union + { + struct telnetio_s *tn; + struct redirect_s rd; + } u; +}; + struct telnetd_s { - struct nsh_vtbl_s vtbl; - int tn_sockfd; - uint16 tn_sndlen; - uint8 tn_bufndx; - uint8 tn_state; - char tn_iobuffer[CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE]; - char tn_cmd[CONFIG_EXAMPLES_NSH_LINELEN]; + struct nsh_vtbl_s tn_vtbl; + boolean tn_redirected; + int tn_refs; /* Reference counts on the instance */ + union + { + struct telnetio_s *tn; + struct redirect_s rd; + } u; + char tn_cmd[CONFIG_EXAMPLES_NSH_LINELEN]; }; /**************************************************************************** @@ -102,9 +130,11 @@ static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl); static void nsh_telnetaddref(FAR struct nsh_vtbl_s *vtbl); static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl); 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 FAR void *nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd); -static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR void *direct); +static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR ubyte *save); +static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR ubyte *save); +static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl); /**************************************************************************** * Private Functions @@ -164,23 +194,79 @@ static void nsh_dumpbuffer(const char *msg, const char *buffer, ssize_t nbytes) * Name: nsh_allocstruct ****************************************************************************/ -static inline FAR struct telnetd_s *nsh_allocstruct(void) +static FAR struct telnetd_s *nsh_allocstruct(void) { struct telnetd_s *pstate = (struct telnetd_s *)malloc(sizeof(struct telnetd_s)); if (pstate) { memset(pstate, 0, sizeof(struct telnetd_s)); - pstate->vtbl.clone = nsh_telnetclone; - pstate->vtbl.addref = nsh_telnetaddref; - pstate->vtbl.release = nsh_telnetrelease; - pstate->vtbl.output = nsh_telnetoutput; - pstate->vtbl.linebuffer = nsh_telnetlinebuffer; - pstate->vtbl.redirect = nsh_telnetredirect; - pstate->vtbl.undirect = nsh_telnetundirect; + pstate->tn_vtbl.clone = nsh_telnetclone; + pstate->tn_vtbl.addref = nsh_telnetaddref; + pstate->tn_vtbl.release = nsh_telnetrelease; + 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; + + pstate->tn_refs = 1; } return pstate; } +/**************************************************************************** + * Name: nsh_openifnotopen + ****************************************************************************/ + +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 + ****************************************************************************/ + +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 * @@ -191,6 +277,8 @@ static inline FAR struct telnetd_s *nsh_allocstruct(void) static void nsh_putchar(struct telnetd_s *pstate, uint8 ch) { + struct telnetio_s *tio = pstate->u.tn; + /* Ignore carriage returns */ if (ch == ISO_cr) @@ -200,25 +288,25 @@ static void nsh_putchar(struct telnetd_s *pstate, uint8 ch) /* Add all other characters to the cmd buffer */ - pstate->tn_cmd[pstate->tn_bufndx] = ch; + pstate->tn_cmd[tio->tio_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_EXAMPLES_NSH_LINELEN - 1)) + if (ch == ISO_nl || tio->tio_bufndx == (CONFIG_EXAMPLES_NSH_LINELEN - 1)) { - if (pstate->tn_bufndx > 0) + if (tio->tio_bufndx > 0) { - pstate->tn_cmd[pstate->tn_bufndx] = '\0'; + pstate->tn_cmd[tio->tio_bufndx] = '\0'; } nsh_dumpbuffer("TELNET CMD", pstate->tn_cmd, strlen(pstate->tn_cmd)); - nsh_parse(&pstate->vtbl, pstate->tn_cmd); - pstate->tn_bufndx = 0; + nsh_parse(&pstate->tn_vtbl, pstate->tn_cmd); + tio->tio_bufndx = 0; } else { - pstate->tn_bufndx++; - vdbg("Add '%c', bufndx=%d\n", ch, pstate->tn_bufndx); + tio->tio_bufndx++; + vdbg("Add '%c', bufndx=%d\n", ch, tio->tio_bufndx); } } @@ -231,6 +319,7 @@ static void nsh_putchar(struct telnetd_s *pstate, uint8 ch) static void nsh_sendopt(struct telnetd_s *pstate, uint8 option, uint8 value) { + struct telnetio_s *tio = pstate->u.tn; uint8 optbuf[4]; optbuf[0] = TELNET_IAC; optbuf[1] = option; @@ -238,9 +327,9 @@ static void nsh_sendopt(struct telnetd_s *pstate, uint8 option, uint8 value) optbuf[3] = 0; nsh_dumpbuffer("Send optbuf", optbuf, 4); - if (send(pstate->tn_sockfd, optbuf, 4, 0) < 0) + if (send(tio->tio_sockfd, optbuf, 4, 0) < 0) { - dbg("[%d] Failed to send TELNET_IAC\n", pstate->tn_sockfd); + dbg("[%d] Failed to send TELNET_IAC\n", tio->tio_sockfd); } } @@ -254,15 +343,17 @@ static void nsh_sendopt(struct telnetd_s *pstate, uint8 option, uint8 value) static void nsh_flush(FAR struct telnetd_s *pstate) { - if (pstate->tn_sndlen > 0) + struct telnetio_s *tio = pstate->u.tn; + + if (tio->tio_sndlen > 0) { - nsh_dumpbuffer("Shell output", pstate->tn_iobuffer, pstate->tn_sndlen); - if (send(pstate->tn_sockfd, pstate->tn_iobuffer, pstate->tn_sndlen, 0) < 0) + nsh_dumpbuffer("Shell output", tio->tio_buffer, tio->tio_sndlen); + if (send(tio->tio_sockfd, tio->tio_buffer, tio->tio_sndlen, 0) < 0) { - dbg("[%d] Failed to send response\n", pstate->tn_sockfd); + dbg("[%d] Failed to send response\n", tio->tio_sockfd); } } - pstate->tn_sndlen = 0; + tio->tio_sndlen = 0; } /**************************************************************************** @@ -275,7 +366,8 @@ static void nsh_flush(FAR struct telnetd_s *pstate) static int nsh_receive(struct telnetd_s *pstate, size_t len) { - char *ptr = pstate->tn_iobuffer; + struct telnetio_s *tio = pstate->u.tn; + char *ptr = tio->tio_buffer; uint8 ch; while (len > 0) @@ -283,37 +375,37 @@ static int nsh_receive(struct telnetd_s *pstate, size_t len) ch = *ptr++; len--; - vdbg("ch=%02x state=%d\n", ch, pstate->tn_state); - switch (pstate->tn_state) + 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); - pstate->tn_state = STATE_NORMAL; + tio->tio_state = STATE_NORMAL; } else { switch (ch) { case TELNET_WILL: - pstate->tn_state = STATE_WILL; + tio->tio_state = STATE_WILL; break; case TELNET_WONT: - pstate->tn_state = STATE_WONT; + tio->tio_state = STATE_WONT; break; case TELNET_DO: - pstate->tn_state = STATE_DO; + tio->tio_state = STATE_DO; break; case TELNET_DONT: - pstate->tn_state = STATE_DONT; + tio->tio_state = STATE_DONT; break; default: - pstate->tn_state = STATE_NORMAL; + tio->tio_state = STATE_NORMAL; break; } } @@ -323,34 +415,34 @@ static int nsh_receive(struct telnetd_s *pstate, size_t len) /* Reply with a DONT */ nsh_sendopt(pstate, TELNET_DONT, ch); - pstate->tn_state = STATE_NORMAL; + tio->tio_state = STATE_NORMAL; break; case STATE_WONT: /* Reply with a DONT */ nsh_sendopt(pstate, TELNET_DONT, ch); - pstate->tn_state = STATE_NORMAL; + tio->tio_state = STATE_NORMAL; break; case STATE_DO: /* Reply with a WONT */ nsh_sendopt(pstate, TELNET_WONT, ch); - pstate->tn_state = STATE_NORMAL; + tio->tio_state = STATE_NORMAL; break; case STATE_DONT: /* Reply with a WONT */ nsh_sendopt(pstate, TELNET_WONT, ch); - pstate->tn_state = STATE_NORMAL; + tio->tio_state = STATE_NORMAL; break; case STATE_NORMAL: if (ch == TELNET_IAC) { - pstate->tn_state = STATE_IAC; + tio->tio_state = STATE_IAC; } else { @@ -374,24 +466,26 @@ static int nsh_receive(struct telnetd_s *pstate, size_t len) static void *nsh_connection(void *arg) { - struct telnetd_s *pstate = nsh_allocstruct(); - int sockfd = (int)arg; - int ret = ERROR; + struct telnetd_s *pstate = nsh_allocstruct(); + struct telnetio_s *tio = (struct telnetio_s *)malloc(sizeof(struct telnetio_s)); + int sockfd = (int)arg; + int ret = ERROR; dbg("[%d] Started\n", sockfd); /* Verify that the state structure was successfully allocated */ - if (pstate) + if (pstate && tio) { /* Initialize the thread state structure */ - pstate->tn_sockfd = sockfd; - pstate->tn_state = STATE_NORMAL; + tio->tio_sockfd = sockfd; + tio->tio_state = STATE_NORMAL; + pstate->u.tn = tio; /* Output a greeting */ - nsh_output(&pstate->vtbl, "NuttShell (NSH)\n"); + nsh_output(&pstate->tn_vtbl, "NuttShell (NSH)\n"); /* Loop processing each TELNET command */ @@ -399,30 +493,38 @@ static void *nsh_connection(void *arg) { /* Display the prompt string */ - nsh_output(&pstate->vtbl, g_nshprompt); + nsh_output(&pstate->tn_vtbl, g_nshprompt); nsh_flush(pstate); /* Read a buffer of data from the TELNET client */ - ret = recv(pstate->tn_sockfd, pstate->tn_iobuffer, CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE, 0); + ret = recv(tio->tio_sockfd, tio->tio_buffer, CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE, 0); if (ret > 0) { /* Process the received TELNET data */ - nsh_dumpbuffer("Received buffer", pstate->tn_iobuffer, ret); + nsh_dumpbuffer("Received buffer", pstate->u.tn.tio_buffer, ret); ret = nsh_receive(pstate, ret); } } - while (ret >= 0 && pstate->tn_state != STATE_CLOSE); - dbg("[%d] ret=%d tn_state=%d\n", sockfd, ret, pstate->tn_state); + 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 */ + if (pstate) + { free(pstate); } - /* Exit the task */ + if (tio) + { + free(tio); + } dbg("[%d] Exitting\n", sockfd); close(sockfd); @@ -443,17 +545,18 @@ static void *nsh_connection(void *arg) static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) { - struct telnetd_s *pstate = (struct telnetd_s *)vtbl; - int nbytes = pstate->tn_sndlen; - int len; - va_list ap; + struct telnetd_s *pstate = (struct telnetd_s *)vtbl; + struct telnetio_s *tio = pstate->u.tn; + int nbytes = tio->tio_sndlen; + int len; + va_list ap; /* Put the new info into the buffer. Here we are counting on the fact that * no output strings will exceed CONFIG_EXAMPLES_NSH_LINELEN! */ va_start(ap, fmt); - vsnprintf(&pstate->tn_iobuffer[nbytes], + vsnprintf(&tio->tio_buffer[nbytes], (CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE - 1) - nbytes, fmt, ap); va_end(ap); @@ -461,20 +564,20 @@ static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) * buffered data */ - len = strlen(&pstate->tn_iobuffer[nbytes]); + len = strlen(&tio->tio_buffer[nbytes]); nbytes += len; /* Expand any terminating \n to \r\n */ if (nbytes < (CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE - 2) && - pstate->tn_iobuffer[nbytes-1] == '\n') + tio->tio_buffer[nbytes-1] == '\n') { - pstate->tn_iobuffer[nbytes-1] = ISO_cr; - pstate->tn_iobuffer[nbytes] = ISO_nl; - pstate->tn_iobuffer[nbytes+1] = '\0'; + tio->tio_buffer[nbytes-1] = ISO_cr; + tio->tio_buffer[nbytes] = ISO_nl; + tio->tio_buffer[nbytes+1] = '\0'; nbytes++; } - pstate->tn_sndlen = nbytes; + tio->tio_sndlen = nbytes; /* Flush to the network if the buffer does not have room for one more * maximum length string. @@ -488,13 +591,44 @@ static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) 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) { @@ -502,6 +636,134 @@ static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl) return pstate->tn_cmd; } +/**************************************************************************** + * Name: nsh_telnetclone + * + * Description: + * Make an independent copy of the vtbl + * + ****************************************************************************/ + +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(); + + 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; + return &pclone->tn_vtbl; +} + +/**************************************************************************** + * Name: nsh_telnetaddref + * + * Description: + * Increment the reference count on the vtbl. + * + ****************************************************************************/ + +static void nsh_telnetaddref(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + pstate->tn_refs++; +} + +/**************************************************************************** + * Name: nsh_telnetrelease + * + * Description: + * Decrement the reference count on the vtbl, releasing it when the count + * decrements to zero. + * + ****************************************************************************/ + +static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + if (pstate->tn_refs > 1) + { + pstate->tn_refs--; + } + else + { + DEBUGASSERT(pstate->tn_redirected); + nsh_closeifnotclosed(pstate); + free(vtbl); + } +} + +/**************************************************************************** + * Name: nsh_telnetredirect + * + * Description: + * Set up for redirected output + * + ****************************************************************************/ + +static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR ubyte *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_telnetredirect + * + * Description: + * Set up for redirected output + * + ****************************************************************************/ + +static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR ubyte *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 ****************************************************************************/ @@ -596,18 +858,3 @@ int nsh_telnetmain(int argc, char *argv[]) uip_server(HTONS(23), nsh_connection, CONFIG_EXAMPLES_NSH_STACKSIZE); return OK; } - -/**************************************************************************** - * Name: cmd_exit - * - * Description: - * Quit the shell instance - * - ****************************************************************************/ - -void cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) -{ - struct telnetd_s *pstate = (struct telnetd_s *)vtbl; - pstate->tn_state = STATE_CLOSE; -} - -- cgit v1.2.3