diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-04-17 08:08:01 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-04-17 08:08:01 +0300 |
commit | 49c3bbde51405d9b37618f718af953e8076fc17e (patch) | |
tree | 554e0a80d39d7991b6859d879744edd7212245b1 | |
parent | 49090e5d3c3acc8f392acba9facb87c2313d323d (diff) | |
download | rpipe-49c3bbde51405d9b37618f718af953e8076fc17e.tar.gz rpipe-49c3bbde51405d9b37618f718af953e8076fc17e.tar.bz2 |
Various bugfixes
* Makefile: Add new source.
* client.c: Rewrite crlfdot decoder; move it to a separate file.
* crlfdot.c: New file.
* iobuf.h (iobuf_putback): Return previous character.
* rpipe.h (crlfdot_encoder_state)
(crlfdot_decoder_state): New data types.
(crlfdot_encoder,crlfdot_decoder): New functions.
* server.c (srv_net_out): Don't disconnect until all input from the
program has been computed (i.e. the pollout server clears the POLLIN
bit).
(progout_transfer): Similarly, wait with appending the exit status
info to the output buffer.
(net_setup): Make sure all fields in rpipe_t are properly initialized.
Fix counting of events in the main loop. Handle POLLHUP event separately.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | client.c | 105 | ||||
-rw-r--r-- | crlfdot.c | 131 | ||||
-rw-r--r-- | iobuf.h | 2 | ||||
-rw-r--r-- | rpipe.h | 26 | ||||
-rw-r--r-- | server.c | 76 |
6 files changed, 174 insertions, 168 deletions
@@ -17,7 +17,7 @@ CFLAGS = -Wall -ggdb # ############################ # Configurable part ends here # ############################ -SOURCES = rpipe.c net.c mem.c wordsplit.c server.c client.c runas.c +SOURCES = rpipe.c net.c mem.c wordsplit.c server.c client.c runas.c crlfdot.c HEADERS = rpipe.h iobuf.h wordsplit.h OBJECTS = $(SOURCES:.c=.o) DOCS = COPYING README @@ -40,106 +40,7 @@ struct rpipe_client { struct iobuf ibuf; /* Input buffer */ struct iobuf obuf; /* Output buffer */ }; - -enum crlfdot_decode_state { - crlfdot_decode_init, /* initial state */ - crlfdot_decode_char, /* Any character excepting [\r\n.] */ - crlfdot_decode_cr, /* prev. char was \r */ - crlfdot_decode_crlf, /* 2 prev. char were \r\n */ - crlfdot_decode_dot, /* 3 prev. chars were \r\n. */ - crlfdot_decode_dotcr, /* 4 prev. chars were \r\n.\r */ - crlfdot_decode_end /* final state, a \r\n.\r\n seen. */ -}; - -static enum crlfdot_decode_state -new_decode_state (enum crlfdot_decode_state state, int c) -{ - switch (state) { - case crlfdot_decode_init: - switch (c) { - case '\r': - return crlfdot_decode_cr; - case '.': - return crlfdot_decode_dot; - } - break; - - case crlfdot_decode_char: - switch (c) { - case '\r': - return crlfdot_decode_cr; - } - break; - - case crlfdot_decode_cr: - switch (c) { - case '\r': - return crlfdot_decode_cr; - case '\n': - return crlfdot_decode_crlf; - } - break; - - case crlfdot_decode_crlf: - switch (c) { - case '\r': - return crlfdot_decode_cr; - case '.': - return crlfdot_decode_dot; - } - - case crlfdot_decode_dot: - switch (c) { - case '\r': - return crlfdot_decode_dotcr; - } - break; - - case crlfdot_decode_dotcr: - switch (c) { - case '\n': - return crlfdot_decode_end; - } - - case crlfdot_decode_end: - break; - } - return crlfdot_decode_char; -} - -static void -crlfdot_decoder(enum crlfdot_decode_state *pstate, struct iobuf *obuf, - struct iobuf *ibuf) -{ - while (*pstate != crlfdot_decode_end - && iobuf_avail_size(obuf) && iobuf_data_size(ibuf)) { - int c = iobuf_getc(ibuf); - int newstate = new_decode_state(*pstate, c); - - if (c == '\r') { - c = iobuf_getc(ibuf); - if (c == -1) - break; - if (c == '\n') - newstate = new_decode_state(newstate, c); - else - c = iobuf_putback(ibuf); - } else if (c == '.' && - (*pstate == crlfdot_decode_init || - *pstate == crlfdot_decode_crlf)) { - c = iobuf_getc(ibuf); - if (c == -1) - break; - if (c == '.') - newstate = new_decode_state(newstate, c); - else - c = iobuf_putback(ibuf); - } - iobuf_putc(obuf, c); - *pstate = newstate; - } -} - + static int valid_pollfd(struct pollfd *pf, int n) { @@ -162,7 +63,7 @@ waitreply(int fd) }; struct pollfd fds[NFD]; struct rpipe_client client[NFD]; - enum crlfdot_decode_state state = crlfdot_decode_init; + struct crlfdot_decoder_state state = CRLFDOT_DECODER_STATE_INIT; memset(&fds, 0, sizeof(fds)); fds[NET].fd = fd; @@ -242,7 +143,7 @@ waitreply(int fd) } } - if (state == crlfdot_decode_end && iobuf_data_size(&client[NET].ibuf)) { + if (state.state == -1 && iobuf_data_size(&client[NET].ibuf)) { char *p; unsigned long u = 0; static char dig[] = "0123456789"; diff --git a/crlfdot.c b/crlfdot.c new file mode 100644 index 0000000..fcef819 --- /dev/null +++ b/crlfdot.c @@ -0,0 +1,131 @@ +#include <stdlib.h> +#include <unistd.h> +#include "rpipe.h" +#include "iobuf.h" + +static enum crlfdot_encoder_state +new_encoder_state(int c) +{ + switch (c) { + case '\n': + return crlfdot_encode_lf; + } + return crlfdot_encode_char; +} + +/* Move min(isize,osize) bytes from iptr to optr, byte-stuffing each + '.' appearing at the beginning of a line */ +void +crlfdot_encoder(enum crlfdot_encoder_state *state, + struct iobuf *ibuf, struct iobuf *obuf) +{ + while (iobuf_avail_size(obuf) && iobuf_data_size(ibuf)) { + unsigned char c = iobuf_getc(ibuf); + + if (c == '\n') { + if (iobuf_avail_size(obuf) < 2) + break; + else + iobuf_putc(obuf, '\r'); + } else if (c == '.' + && (*state == crlfdot_encode_init || + *state == crlfdot_encode_lf)) { + if (iobuf_avail_size(obuf) < 2) { + break; + } + iobuf_putc(obuf, '.'); + } + iobuf_putc(obuf, c); + *state = new_encoder_state (c); + } +} + +/* Table-driven CRLFdot decoder. */ +enum symbol { + CR, + LF, + DOT, + CHR +}; + +static char abc[] = "\r\n."; + +static inline int +symbol_of(int c) +{ + int i; + for (i = 0; abc[i] && abc[i] != c; i++) + ; + return i; +} + +enum { + NSYM = 4, + NSTATES = 10 +}; + + +static int transition[NSTATES][NSYM] = { + { 2, 1, 4, 1 }, + { 2, 1, 1, 1 }, + { 6, 3, 6, 6 }, + { 2, 0, 4, 0 }, + { 5, 6, 1, 6 }, + { 7, 8, 7, 7 }, + { 1, 1, 1, 1 }, + { 6, 6, 6, 6 }, + { -1, -1, -1, -1 } +}; + +static int wantinput[NSTATES] = { 1, 1, 1, 1, 1, 1, 0, 0, 0 }; + +enum { + NIL = -1, + INP = -2 +}; + +static int output[NSTATES][NSYM] = { + { NIL, INP, NIL, INP }, + { NIL, INP, INP, INP }, + { CR, INP, CR, CR }, + { NIL, INP, NIL, INP }, + { NIL, DOT, INP, DOT }, + { DOT, NIL, INP, DOT }, + { INP, INP, INP, INP }, + { CR, CR, CR, CR }, + { NIL, NIL, NIL, NIL }, +}; + +void +crlfdot_decoder(struct crlfdot_decoder_state *st, struct iobuf *obuf, + struct iobuf *ibuf) +{ + while (st->state != -1 + && iobuf_avail_size(obuf) && iobuf_data_size(ibuf)) { + int sym, c; + + if (wantinput[st->state]) { + c = iobuf_getc(ibuf); + if (c == -1) { + iobuf_putback(ibuf); + break; + } + st->input = c; + } + sym = symbol_of(st->input); + + c = output[st->state][sym]; + + switch (c) { + case NIL: + break; + case INP: + iobuf_putc(obuf, st->input); + break; + default: + iobuf_putc(obuf, abc[c]); + } + + st->state = transition[st->state][sym]; + } +} @@ -28,7 +28,7 @@ iobuf_data_advance(struct iobuf *bp, size_t n) static inline int iobuf_putback(struct iobuf *bp) { - return bp->buf[--bp->start]; + return bp->buf[--bp->start-1]; } static inline int @@ -22,6 +22,24 @@ struct iobuf { size_t avail; /* Start of available space */ }; +enum crlfdot_encoder_state { + crlfdot_encode_init, /* initial state */ + crlfdot_encode_char, /* Any character except \n */ + crlfdot_encode_lf, /* prev. char was \n */ +}; + +struct crlfdot_decoder_state { + int state; + int input; +}; + +#define CRLFDOT_DECODER_STATE_INIT { 0, 0 } + +void crlfdot_encoder(enum crlfdot_encoder_state *state, + struct iobuf *ibuf, struct iobuf *obuf); +void crlfdot_decoder(struct crlfdot_decoder_state *st, + struct iobuf *obuf, struct iobuf *ibuf); + struct sockaddr; char *sockaddr_str(struct sockaddr *sa, int salen); struct addrinfo; @@ -110,12 +128,6 @@ struct rpipe_server_prog { /* Program input server */ struct rpipe_server_progout *out; }; -enum dot_encode_state { - dot_encode_init, /* initial state */ - dot_encode_char, /* Any character except \n */ - dot_encode_lf, /* prev. char was \n */ -}; - /* Status buffer contains CRLF 2 exit status (max. 65535) 5 @@ -134,7 +146,7 @@ struct rpipe_server_progout { /* Program output server */ /* Server-specific part */ struct rpipe_server_prog *prog; /* Corresponding prog */ struct iobuf buf; /* Input buffer */ - enum dot_encode_state encode_state; + enum crlfdot_encoder_state encode_state; char status_buffer[STATUS_BUFFER_SIZE]; size_t status_index; }; @@ -229,48 +229,6 @@ iobuf_transfer(struct iobuf *dst, struct iobuf *src) return 0; } -static enum dot_encode_state -new_encode_state(int c) -{ - switch (c) { - case '\n': - return dot_encode_lf; - } - return dot_encode_char; -} - -/* Move min(isize,osize) bytes from iptr to optr, byte-stuffing each - '.' appearing at the beginning of a line */ -static ssize_t -dot_encoder(enum dot_encode_state *state, - struct iobuf *ibuf, struct iobuf *obuf) -{ - ssize_t n = 0; - - while (iobuf_avail_size(obuf) && iobuf_data_size(ibuf)) { - unsigned char c = iobuf_getc(ibuf); - - if (c == '\n') { - if (iobuf_avail_size(obuf) < 2) - break; - else - iobuf_putc(obuf, '\r'); - } else if (c == '.' - && (*state == dot_encode_init || - *state == dot_encode_lf)) { - if (iobuf_avail_size(obuf) < 2) { - break; - } - iobuf_putc(obuf, '.'); - } - iobuf_putc(obuf, c); - *state = new_encode_state (c); - n++; - } - - return n; -} - /* ************************** * Particular server types * ************************** */ @@ -539,7 +497,7 @@ srv_net_out(rpipe_t *rp, rpipe_server_t *srv) progout_transfer(net->progout, net); if (iobuf_data_size(&net->obuf) == 0) { - if (!net->prog) + if (!net->prog && !(net->progout->pollfd->events & POLLIN)) rpipe_server_disconnect(rp, srv); return 0; } @@ -739,22 +697,23 @@ progout_store_status(struct rpipe_server_progout *p, int status) } progout_crlf(p); p->status_buffer[p->status_index++] = '.'; - if (p->encode_state != dot_encode_init) + if (p->encode_state == crlfdot_encode_char) progout_crlf(p); } static void progout_transfer(struct rpipe_server_progout *p, struct rpipe_server_net *net) { - dot_encoder(&p->encode_state, &p->buf, &net->obuf); - - while (p->status_index > 0) { - if (iobuf_putc(&net->obuf, - p->status_buffer[p->status_index-1]) - == -1) - break; - p->status_index--; - } + crlfdot_encoder(&p->encode_state, &p->buf, &net->obuf); + if (!(p->pollfd->events & POLLIN)) { + while (p->status_index > 0) { + if (iobuf_putc(&net->obuf, + p->status_buffer[p->status_index-1]) + == -1) + break; + p->status_index--; + } + } } @@ -770,7 +729,7 @@ net_setup(struct addrinfo *res, int np, int argc, char **argv) for (ap = res; ap; ap = ap->ai_next) nf++; - rp = xmalloc(sizeof(*rp)); + rp = xcalloc(1, sizeof(*rp)); rp->maxconn = np; rp->nfd = nf + 2*np; rp->fds = xcalloc(rp->nfd, sizeof(rp->fds[0])); @@ -852,7 +811,6 @@ proc_cleanup(rpipe_t *rp) { pid_t pid; int status; - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { struct rpipe_server_prog *prog = rpipe_server_by_pid(rp, pid); if (!prog) { @@ -922,13 +880,18 @@ rpipe_server(struct addrinfo *ap, int np, int argc, char **argv) error(0, errno, "poll"); continue; } + for (i = 0; n > 0 && i < rp->nfd; i++) { + if (rp->fds[i].revents) + n--; if (rp->fds[i].fd < 0) continue; - if (rp->fds[i].events & rp->fds[i].revents) { + if ((rp->fds[i].events|POLLHUP) & rp->fds[i].revents) { int rc = 0; rpipe_server_t *srv = &rp->srv[i]; + if (rp->fds[i].revents & POLLHUP) + rp->fds[i].events = 0; if (rp->fds[i].revents & POLLIN) rc |= rpipe_server_input(rp, srv); if (rp->fds[i].revents & POLLOUT) @@ -937,7 +900,6 @@ rpipe_server(struct addrinfo *ap, int np, int argc, char **argv) //FIXME rpipe_server_disconnect(rp, srv); } - n--; } } } |