aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-04-17 08:08:01 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-04-17 08:08:01 +0300
commit49c3bbde51405d9b37618f718af953e8076fc17e (patch)
tree554e0a80d39d7991b6859d879744edd7212245b1
parent49090e5d3c3acc8f392acba9facb87c2313d323d (diff)
downloadrpipe-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--Makefile2
-rw-r--r--client.c105
-rw-r--r--crlfdot.c131
-rw-r--r--iobuf.h2
-rw-r--r--rpipe.h26
-rw-r--r--server.c76
6 files changed, 174 insertions, 168 deletions
diff --git a/Makefile b/Makefile
index 13e4d8c..739ee6f 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/client.c b/client.c
index 18ce342..ddff286 100644
--- a/client.c
+++ b/client.c
@@ -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];
+ }
+}
diff --git a/iobuf.h b/iobuf.h
index 9e304f1..b91eece 100644
--- a/iobuf.h
+++ b/iobuf.h
@@ -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
diff --git a/rpipe.h b/rpipe.h
index e47c4aa..c7c6cfd 100644
--- a/rpipe.h
+++ b/rpipe.h
@@ -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;
};
diff --git a/server.c b/server.c
index a88c9b6..2869d67 100644
--- a/server.c
+++ b/server.c
@@ -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--;
}
}
}

Return to:

Send suggestions and report system problems to the System administrator.