Skip to content

Commit

Permalink
Successfully integrate linenoise with web server
Browse files Browse the repository at this point in the history
In the previous version of console implementation, we tried to integrate
tiny-web-server to enable the ability of processing commands from web
requests. As the result, the package linenoise which is responsible for
command-line auto-complete needs to be disabled during the running time
of tiny-web-server. Because the `line_edit()` function in linenoise.c
doesn't have the ability to handle web requests correctly.

When we start the web server, we use `cmd_select` in console.c and use
`select` system call to monitor web socket file descriptor and stdin_fd
at the same time, however, this ability should present in the
`line_edit` function in linenoise.c so we can process commands from
command-line and from web requests at the same time.

That's the reason I re-design the linenoise implementation and make some
modification to put `select()` system call in `line_edit` so we can have
the full ability to use web server and linenoise package in command-line
at the same time.
  • Loading branch information
vax-r committed Feb 29, 2024
1 parent 69e89c1 commit f6aff4f
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 100 deletions.
106 changes: 7 additions & 99 deletions console.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ typedef struct __rio {
} rio_t;

static rio_t *buf_stack;
static char linebuf[RIO_BUFSIZE];

/* Maximum file descriptor */
static int fd_max = 0;
Expand Down Expand Up @@ -405,6 +404,7 @@ static bool do_web(int argc, char *argv[])
web_fd = web_open(port);
if (web_fd > 0) {
printf("listen on port %d, fd is %d\n", port, web_fd);
linenoise_webfd(web_fd);
use_linenoise = false;
} else {
perror("ERROR");
Expand Down Expand Up @@ -483,61 +483,6 @@ static void init_in()
buf_stack = NULL;
}

/* Read command from input file.
* When hit EOF, close that file and return NULL
*/
static char *readline()
{
char c;
char *lptr = linebuf;

if (!buf_stack)
return NULL;

for (int cnt = 0; cnt < RIO_BUFSIZE - 2; cnt++) {
if (buf_stack->count <= 0) {
/* Need to read from input file */
buf_stack->count = read(buf_stack->fd, buf_stack->buf, RIO_BUFSIZE);
buf_stack->bufptr = buf_stack->buf;
if (buf_stack->count <= 0) {
/* Encountered EOF */
pop_file();
if (cnt > 0) {
/* Last line of file did not terminate with newline. */
/* Terminate line & return it */
*lptr++ = '\n';
*lptr++ = '\0';
if (echo) {
report_noreturn(1, prompt);
report_noreturn(1, linebuf);
}
return linebuf;
}
return NULL;
}
}

/* Have text in buffer */
c = *buf_stack->bufptr++;
*lptr++ = c;
buf_stack->count--;
if (c == '\n')
break;
}

if (c != '\n') {
/* Hit buffer limit. Artificially terminate line */
*lptr++ = '\n';
}
*lptr++ = '\0';

if (echo) {
report_noreturn(1, prompt);
report_noreturn(1, linebuf);
}

return linebuf;
}

static bool cmd_done()
{
Expand All @@ -560,13 +505,13 @@ static int cmd_select(int nfds,
fd_set *exceptfds,
struct timeval *timeout)
{
int infd;
fd_set local_readset;

if (cmd_done())
return 0;

if (!block_flag) {
int infd;
/* Process any commands in input buffer */
if (!readfds)
readfds = &local_readset;
Expand All @@ -581,51 +526,14 @@ static int cmd_select(int nfds,
FD_SET(web_fd, readfds);

if (infd == STDIN_FILENO && prompt_flag) {
printf("%s", prompt);
char *cmdline = linenoise(prompt);
if (cmdline)
interpret_cmd(cmdline);
fflush(stdout);
prompt_flag = true;
}

if (infd >= nfds)
nfds = infd + 1;
if (web_fd >= nfds)
nfds = web_fd + 1;
}
if (nfds == 0)
return 0;

int result = select(nfds, readfds, writefds, exceptfds, timeout);
if (result <= 0)
return result;

infd = buf_stack->fd;
if (readfds && FD_ISSET(infd, readfds)) {
/* Commandline input available */
FD_CLR(infd, readfds);
result--;

set_echo(0);
char *cmdline = readline();
if (cmdline)
interpret_cmd(cmdline);
} else if (readfds && FD_ISSET(web_fd, readfds)) {
FD_CLR(web_fd, readfds);
result--;
struct sockaddr_in clientaddr;
socklen_t clientlen = sizeof(clientaddr);
web_connfd =
accept(web_fd, (struct sockaddr *) &clientaddr, &clientlen);

char *p = web_recv(web_connfd, &clientaddr);
char *buffer = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
web_send(web_connfd, buffer);

if (p)
interpret_cmd(p);
free(p);
close(web_connfd);
}
return result;
return 0;
}

bool finish_cmd()
Expand Down Expand Up @@ -706,4 +614,4 @@ bool run_console(char *infile_name)
}

return err_cnt == 0;
}
}
44 changes: 43 additions & 1 deletion linenoise.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,20 @@

#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>

#include "linenoise.h"
#include "web.h"

#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 4096
Expand Down Expand Up @@ -180,6 +183,9 @@ static void line_atexit(void);
int line_history_add(const char *line);
static void refresh_line(struct line_state *l);

int web_fd;
bool listen_web = false;

/* Debugging macro. */
#if 0
FILE *lndebug_fp = NULL;
Expand Down Expand Up @@ -927,6 +933,36 @@ static int line_edit(int stdin_fd,

if (write(l.ofd, prompt, l.plen) == -1)
return -1;

fd_set set;

int max_fd = stdin_fd;
FD_ZERO(&set);
if (listen_web) {
FD_SET(web_fd, &set);
max_fd = max_fd > web_fd ? max_fd : web_fd;
}
FD_SET(stdin_fd, &set);
int result = select(max_fd + 1, &set, NULL, NULL, NULL);
if (result < 0)
return -1;

if (listen_web && FD_ISSET(web_fd, &set)) {
FD_CLR(web_fd, &set);
struct sockaddr_in clientaddr;
socklen_t clientlen = sizeof(clientaddr);
int web_connfd =
accept(web_fd, (struct sockaddr *) &clientaddr, &clientlen);

char *p = web_recv(web_connfd, &clientaddr);
char *buffer = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
web_send(web_connfd, buffer);
strncpy(buf, p, strlen(p) + 1);
free(p);
close(web_connfd);
return strlen(buf);
}

while (1) {
signed char c;
int nread;
Expand Down Expand Up @@ -1215,6 +1251,12 @@ char *linenoise(const char *prompt)
return strdup(buf);
}

void linenoise_webfd(int fd)
{
web_fd = fd;
listen_web = true;
}

/* This is just a wrapper the user may want to call in order to make sure
* the linenoise returned buffer is freed with the same allocator it was
* created with. Useful when the main program is using an alternative
Expand Down Expand Up @@ -1362,4 +1404,4 @@ int line_history_load(const char *filename)
}
fclose(fp);
return 0;
}
}
1 change: 1 addition & 0 deletions linenoise.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void line_set_free_hints_callback(line_free_hints_callback_t *);
void line_add_completion(line_completions_t *, const char *);
/* clang-format on */

void linenoise_webfd(int fd);
char *linenoise(const char *prompt);
void line_free(void *ptr);
int line_history_add(const char *line);
Expand Down

0 comments on commit f6aff4f

Please sign in to comment.