Concurrent telnet+serial

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@824 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2008-08-16 20:52:06 +00:00
parent 266c90f8b1
commit 161898863a
4 changed files with 411 additions and 134 deletions

View File

@ -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

View File

@ -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

View File

@ -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_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;
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);
}

View File

@ -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 <spudmonkey@racsa.co.cr>
*
* This is a leverage of similar logic from uIP:
@ -51,6 +51,7 @@
#include <stdarg.h>
#include <string.h>
#include <pthread.h>
#include <assert.h>
#include <debug.h>
#include <net/if.h>
@ -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,31 +493,39 @@ 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 */
free(pstate);
}
/* Exit the task */
if (pstate)
{
free(pstate);
}
if (tio)
{
free(tio);
}
dbg("[%d] Exitting\n", sockfd);
close(sockfd);
pthread_exit(NULL);
@ -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;
}