ref: 290a0bec7f7c1328a98ac7a367de62f8d5d6b2b7
parent: 1bfefe551389909d88c22c51f3c33a524cebf827
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Dec 23 07:44:19 EST 2019
process all the incoming data first, then send out the responses
--- a/9pex.c
+++ b/9pex.c
@@ -93,7 +93,7 @@
static C9qid walkqids[C9maxpathel];
static uint8_t *rdbuf;
static uint8_t *wrbuf;
-static int wroff;
+static uint32_t wroff, wrend, wrbufsz;
__attribute__ ((format (printf, 1, 2)))
static void
@@ -110,7 +110,7 @@
}
static int
-canrw(int rdonly)
+canrw(int rdonly, int block)
{
struct timeval t;
fd_set r, w, e;
@@ -118,16 +118,15 @@
FD_ZERO(&r);
FD_SET(in, &r);
- if (rdonly == 0) {
- FD_ZERO(&w);
+ FD_ZERO(&w);
+ if (rdonly == 0)
FD_SET(out, &w);
- }
FD_ZERO(&e);
FD_SET(in, &e);
FD_SET(out, &e);
memset(&t, 0, sizeof(t));
t.tv_usec = 1000;
- if ((n = select(max(in, out) + 1, &r, &w, &e, rdonly ? NULL : &t)) < 0 || FD_ISSET(in, &e) || FD_ISSET(out, &e))
+ if ((n = select(max(in, out) + 1, &r, &w, &e, block ? NULL : &t)) < 0 || FD_ISSET(in, &e) || FD_ISSET(out, &e))
return -1;
fl = 0;
@@ -140,6 +139,21 @@
}
static int
+wrsend(void)
+{
+ if (wrend == 0)
+ return 0;
+ if (write(out, wrbuf, wrend) != wrend) {
+ perror("write");
+ return -1;
+ }
+ memmove(wrbuf, wrbuf+wrend, wroff-wrend);
+ wroff = wroff - wrend;
+
+ return 0;
+}
+
+static int
hastag(C9tag tag)
{
int i;
@@ -473,6 +487,10 @@
uint8_t *b;
used(c);
+ if (wroff + size > wrbufsz) {
+ if (wrsend() != 0 || wroff + size > wrbufsz)
+ return NULL;
+ }
b = wrbuf + wroff;
wroff += size;
@@ -483,11 +501,7 @@
ctxend(C9ctx *c)
{
used(c);
-
- if (write(out, wrbuf, wroff) != wroff)
- return -1;
- wroff = 0;
-
+ wrend = wroff;
return 0;
}
@@ -716,7 +730,7 @@
char *err;
Fid *f;
struct parg_state ps;
- int can, i, c;
+ int can, i, c, rdonly, block;
parg_init(&ps);
@@ -777,15 +791,32 @@
ctx.error = ctxerror;
rdbuf = calloc(1, ctx.msize);
- wrbuf = calloc(1, ctx.msize);
- wroff = 0;
+ wrbufsz = ctx.msize;
+ wrbuf = calloc(1, wrbufsz);
+ wroff = wrend = 0;
err = NULL;
+ rdonly = block = 1; /* at first we wait until the client sends in data */
for (; !eof;) {
- if ((can = canrw(1)) < 0)
+ if ((can = canrw(rdonly, block)) < 0)
break;
- if ((can & Canrd) != 0 && s9do(s9proc(&ctx), &err) != 0)
- break;
+ if ((can & Canrd) != 0) { /* if there is data, process it */
+ if (s9do(s9proc(&ctx), &err) != 0)
+ break;
+ /* give it a chance to receive all the data first */
+ rdonly = 1;
+ block = 0;
+ } else if (block == 0) { /* got all the data */
+ if (rdonly != 0) { /* wait until we can send OR we get more data */
+ rdonly = 0;
+ block = 1;
+ }
+ } else if (rdonly == 0 && (can & Canwr) != 0) { /* can send */
+ if (wrsend() != 0) /* send all the data */
+ break;
+ rdonly = 1; /* and go back to reading */
+ block = 1;
+ }
}
if (err != NULL)