Merge branch 'master' into duplex
authorFredrik Tolf <fredrik@dolda2000.com>
Wed, 18 May 2016 03:58:50 +0000 (05:58 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Wed, 18 May 2016 03:58:50 +0000 (05:58 +0200)
16 files changed:
lib/Makefile.am
lib/bufio.c [new file with mode: 0644]
lib/bufio.h [new file with mode: 0644]
lib/mtio-epoll.c
lib/mtio-kqueue.c
lib/mtio-select.c
lib/mtio.c
lib/mtio.h
lib/req.c
lib/req.h
python3/ashd-wsgi3
src/accesslog.c
src/htparser.c
src/htparser.h
src/plaintcp.c
src/ssl-gnutls.c

index 30de42a..0f13d2b 100644 (file)
@@ -1,6 +1,7 @@
 lib_LIBRARIES = libht.a
 
-libht_a_SOURCES =      utils.c mt.c log.c req.c proc.c mtio.c resp.c cf.c
+libht_a_SOURCES =      utils.c mt.c log.c req.c proc.c mtio.c resp.c \
+                       cf.c bufio.c
 libht_a_CFLAGS =       -fPIC
 if USE_EPOLL
 libht_a_SOURCES += mtio-epoll.c
@@ -12,4 +13,5 @@ libht_a_SOURCES += mtio-select.c
 endif
 endif
 
-pkginclude_HEADERS =   utils.h mt.h log.h req.h proc.h mtio.h resp.h cf.h
+pkginclude_HEADERS =   utils.h mt.h log.h req.h proc.h mtio.h resp.h \
+                       cf.h bufio.h
diff --git a/lib/bufio.c b/lib/bufio.c
new file mode 100644 (file)
index 0000000..c08e9dd
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+    ashd - A Sane HTTP Daemon
+    Copyright (C) 2008  Fredrik Tolf <fredrik@dolda2000.com>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <utils.h>
+#include <bufio.h>
+
+struct bufio *bioopen(void *pdata, struct bufioops *ops)
+{
+    struct bufio *bio;
+    
+    omalloc(bio);
+    bio->pdata = pdata;
+    bio->ops = ops;
+    bio->bufhint = 4096;
+    return(bio);
+}
+
+int bioclose(struct bufio *bio)
+{
+    int rv;
+    
+    bioflush(bio);
+    if(bio->ops->close)
+       rv = bio->ops->close(bio->pdata);
+    else
+       rv = 0;
+    buffree(bio->rbuf);
+    buffree(bio->wbuf);
+    free(bio);
+    return(rv);
+}
+
+size_t biordata(struct bufio *bio)
+{
+    return(bio->rbuf.d - bio->rh);
+}
+
+size_t biorspace(struct bufio *bio)
+{
+    if((bio->rbuf.d - bio->rh) >= bio->bufhint)
+       return(0);
+    return(bio->bufhint - (bio->rbuf.d - bio->rh));
+}
+
+int bioeof(struct bufio *bio)
+{
+    return(bio->eof && (bio->rh >= bio->rbuf.d));
+}
+
+static ssize_t biofill(struct bufio *bio)
+{
+    size_t ns;
+    ssize_t ret;
+    
+    if(!bio->ops->read) {
+       bio->eof = 1;
+       return(0);
+    }
+    if(bio->eof)
+       return(0);
+    if(bio->rh == bio->rbuf.d)
+       bio->rh = bio->rbuf.d = 0;
+    if(bio->rbuf.d == bio->rbuf.s) {
+       if(bio->rh > 0) {
+           memmove(bio->rbuf.b, bio->rbuf.b + bio->rh, bio->rbuf.d -= bio->rh);
+           bio->rh = 0;
+       } else {
+           if((ns = bio->rbuf.s * 2) < bio->bufhint)
+               ns = bio->bufhint;
+           sizebuf(bio->rbuf, ns);
+       }
+    }
+    if((bio->rbuf.s > bio->bufhint) && (bio->rbuf.d < bio->bufhint))
+       bio->rbuf.b = srealloc(bio->rbuf.b, bio->rbuf.s = bio->bufhint);
+    ret = bio->ops->read(bio->pdata, bio->rbuf.b + bio->rbuf.d, bio->rbuf.s - bio->rbuf.d);
+    if(ret < 0) {
+       bio->err = errno;
+       return(-1);
+    } else if(ret == 0) {
+       bio->eof = 1;
+       return(0);
+    }
+    bio->rbuf.d += ret;
+    return(bio->rbuf.d - bio->rh);
+}
+
+ssize_t biorensure(struct bufio *bio, size_t bytes)
+{
+    ssize_t ret;
+    
+    while(bio->rbuf.d - bio->rh < bytes) {
+       if((ret = biofill(bio)) <= 0)
+           return(ret);
+    }
+    return(bio->rbuf.d - bio->rh);
+}
+
+ssize_t biofillsome(struct bufio *bio)
+{
+    return(biofill(bio));
+}
+
+int biogetc(struct bufio *bio)
+{
+    ssize_t ret;
+    
+    while(bio->rbuf.d <= bio->rh) {
+       if((ret = biofill(bio)) <= 0)
+           return(EOF);
+    }
+    return((unsigned char)bio->rbuf.b[bio->rh++]);
+}
+
+ssize_t bioreadsome(struct bufio *bio, void *buf, size_t len)
+{
+    ssize_t ret;
+    
+    if((bio->rh >= bio->rbuf.d) && ((ret = biofill(bio)) <= 0))
+       return(ret);
+    ret = min(len, bio->rbuf.d - bio->rh);
+    memcpy(buf, bio->rbuf.b + bio->rh, ret);
+    bio->rh += ret;
+    return(ret);
+}
+
+size_t biowdata(struct bufio *bio)
+{
+    return(bio->wbuf.d - bio->wh);
+}
+
+size_t biowspace(struct bufio *bio)
+{
+    if((bio->wbuf.d - bio->wh) >= bio->bufhint)
+       return(0);
+    return(bio->bufhint - (bio->wbuf.d - bio->wh));
+}
+
+int bioflush(struct bufio *bio)
+{
+    ssize_t ret;
+    
+    while(bio->wh < bio->wbuf.d) {
+       ret = bio->ops->write(bio->pdata, bio->wbuf.b + bio->wh, bio->wbuf.d - bio->wh);
+       if(ret < 0) {
+           bio->err = errno;
+           return(-1);
+       }
+       bio->wh += ret;
+    }
+    return(0);
+}
+
+int bioflushsome(struct bufio *bio)
+{
+    ssize_t ret;
+    
+    if(bio->wh < bio->wbuf.d) {
+       ret = bio->ops->write(bio->pdata, bio->wbuf.b + bio->wh, bio->wbuf.d - bio->wh);
+       if(ret < 0) {
+           bio->err = errno;
+           return(-1);
+       }
+       bio->wh += ret;
+       return(1);
+    } else {
+       return(0);
+    }
+}
+
+ssize_t biowensure(struct bufio *bio, size_t bytes)
+{
+    if(bio->wbuf.s - bio->wbuf.d < bytes) {
+       if(!bio->ops->write) {
+           errno = bio->err = EPIPE;
+           return(-1);
+       }
+       if(bioflush(bio) < 0)
+           return(-1);
+       bio->wh = bio->wbuf.d = 0;
+       if((bio->wbuf.s > bio->bufhint) && (bytes <= bio->bufhint))
+           bio->wbuf.b = srealloc(bio->wbuf.b, bio->wbuf.s = bio->bufhint);
+       else
+           sizebuf(bio->wbuf, (bytes < bio->bufhint)?bio->bufhint:bytes);
+    }
+    return(0);
+}
+
+int bioputc(struct bufio *bio, int c)
+{
+    if(biowensure(bio, 1) < 0)
+       return(-1);
+    bio->wbuf.b[bio->wbuf.d++] = c;
+    return(0);
+}
+
+ssize_t biowrite(struct bufio *bio, const void *data, size_t len)
+{
+    ssize_t wb, ret;
+    
+    wb = 0;
+    while(len > 0) {
+       if(biowensure(bio, min(len, bio->bufhint)) < 0) {
+           if(wb > 0)
+               return(wb);
+           return(-1);
+       }
+       if(len < bio->wbuf.s - bio->wbuf.d) {
+           memcpy(bio->wbuf.b + bio->wbuf.d, data, len);
+           bio->wbuf.d += len;
+           wb += len;
+           len = 0;
+       } else {
+           if(bioflush(bio) < 0) {
+               if(wb > 0)
+                   return(wb);
+               return(-1);
+           }
+           bio->wh = bio->wbuf.d = 0;
+           ret = bio->ops->write(bio->pdata, data, len);
+           if(ret < 0) {
+               if(wb > 0)
+                   return(wb);
+               bio->err = errno;
+               return(-1);
+           }
+           data += ret; len -= ret; wb += ret;
+       }
+    }
+    return(wb);
+}
+
+ssize_t biowritesome(struct bufio *bio, const void *data, size_t len)
+{
+    ssize_t ret;
+    
+    sizebuf(bio->wbuf, bio->bufhint);
+    if(bio->wh == bio->wbuf.d)
+       bio->wh = bio->wbuf.d = 0;
+    if(bio->wbuf.d == bio->wbuf.s) {
+       if(bio->wh > 0) {
+           memmove(bio->wbuf.b, bio->wbuf.b + bio->wh, bio->wbuf.d -= bio->wh);
+           bio->wh = 0;
+       }
+    }
+    ret = min(len, bio->wbuf.s - bio->wbuf.d);
+    memcpy(bio->wbuf.b + bio->wbuf.d, data, ret);
+    bio->wbuf.d += ret;
+    if(bioflushsome(bio) < 0) {
+       if(ret == 0)
+           return(-1);
+       if(ret < bio->wbuf.d - bio->wh) { /* Should never be false */
+           bio->wbuf.d -= ret;
+           return(-1);
+       }
+    }
+    return(ret);
+}
+
+int bioprintf(struct bufio *bio, const char *format, ...)
+{
+    va_list args;
+    int ret;
+    
+    if(biowensure(bio, strlen(format)) < 0)
+       return(-1);
+    while(1) {
+       va_start(args, format);
+       ret = vsnprintf(bio->wbuf.b + bio->wbuf.d, bio->wbuf.s - bio->wbuf.d, format, args);
+       va_end(args);
+       if(ret <= bio->wbuf.s - bio->wbuf.d) {
+           bio->wbuf.d += ret;
+           return(0);
+       }
+       if(biowensure(bio, ret) < 0)
+           return(-1);
+    }
+}
+
+ssize_t biocopysome(struct bufio *dst, struct bufio *src)
+{
+    ssize_t ret;
+    
+    if(src->rh >= src->rbuf.d)
+       return(0);
+    if((ret = biowritesome(dst, src->rbuf.b + src->rh, src->rbuf.d - src->rh)) < 0)
+       return(-1);
+    src->rh += ret;
+    return(ret);
+}
+
+ssize_t biocopybuf(struct bufio *dst, struct bufio *src)
+{
+    ssize_t ret;
+    
+    sizebuf(dst->wbuf, dst->bufhint);
+    if(dst->wbuf.d == dst->wbuf.s) {
+       if(dst->wh > 0) {
+           memmove(dst->wbuf.b, dst->wbuf.b + dst->wh, dst->wbuf.d -= dst->wh);
+           dst->wh = 0;
+       }
+    }
+    ret = min(src->rbuf.d - src->rh, dst->wbuf.s - dst->wbuf.d);
+    memcpy(dst->wbuf.b + dst->wbuf.d, src->rbuf.b + src->rh, ret);
+    src->rh += ret;
+    dst->wbuf.d += ret;
+    return(ret);
+}
diff --git a/lib/bufio.h b/lib/bufio.h
new file mode 100644 (file)
index 0000000..5874577
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _LIB_BUFIO_H
+#define _LIB_BUFIO_H
+
+struct bufioops {
+    ssize_t (*read)(void *pdata, void *buf, size_t len);
+    ssize_t (*write)(void *pdata, const void *buf, size_t len);
+    int (*close)(void *pdata);
+};
+
+struct bufio {
+    struct charbuf rbuf, wbuf;
+    size_t rh, wh, bufhint;
+    int err, eof;
+    void *pdata;
+    struct bufioops *ops;
+};
+
+struct bufio *bioopen(void *pdata, struct bufioops *ops);
+int bioclose(struct bufio *bio);
+
+size_t biordata(struct bufio *bio);
+size_t biorspace(struct bufio *bio);
+int bioeof(struct bufio *bio);
+ssize_t biorensure(struct bufio *bio, size_t bytes);
+ssize_t biofillsome(struct bufio *bio);
+int biogetc(struct bufio *bio);
+ssize_t bioreadsome(struct bufio *bio, void *buf, size_t len);
+
+size_t biowdata(struct bufio *bio);
+size_t biowspace(struct bufio *bio);
+int bioflush(struct bufio *bio);
+int bioflushsome(struct bufio *bio);
+ssize_t biowensure(struct bufio *bio, size_t bytes);
+int bioputc(struct bufio *bio, int c);
+ssize_t biowrite(struct bufio *bio, const void *data, size_t len);
+ssize_t biowritesome(struct bufio *bio, const void *data, size_t len);
+int bioprintf(struct bufio *bio, const char *format, ...);
+ssize_t biocopysome(struct bufio *dst, struct bufio *src);
+ssize_t biocopybuf(struct bufio *dst, struct bufio *src);
+
+#endif
index 72468e0..af7cd27 100644 (file)
@@ -37,7 +37,7 @@ static struct blocker *blockers;
 struct blocker {
     struct blocker *n, *p, *n2, *p2;
     int fd, reg;
-    int ev;
+    int ev, rev, id;
     time_t to;
     struct muth *th;
 };
@@ -129,34 +129,72 @@ static void remfd(struct blocker *bl)
     bl->reg = 0;
 }
 
-int block(int fd, int ev, time_t to)
+static int addblock(struct blocker *bl)
 {
-    struct blocker *bl;
-    int rv;
-    
-    omalloc(bl);
-    bl->fd = fd;
-    bl->ev = ev;
-    if(to > 0)
-       bl->to = time(NULL) + to;
-    bl->th = current;
-    if((epfd >= 0) && regfd(bl)) {
-       free(bl);
+    if((epfd >= 0) && regfd(bl))
        return(-1);
-    }
     bl->n = blockers;
     if(blockers)
        blockers->p = bl;
     blockers = bl;
-    rv = yield();
+    return(0);
+}
+
+static void remblock(struct blocker *bl)
+{
     if(bl->n)
        bl->n->p = bl->p;
     if(bl->p)
        bl->p->n = bl->n;
-    if(bl == blockers)
+    if(blockers == bl)
        blockers = bl->n;
     remfd(bl);
-    free(bl);
+}
+
+struct selected mblock(time_t to, int n, struct selected *spec)
+{
+    int i, id;
+    struct blocker bls[n];
+    
+    to = (to > 0)?(time(NULL) + to):0;
+    for(i = 0; i < n; i++) {
+       bls[i] = (struct blocker) {
+           .fd = spec[i].fd,
+           .ev = spec[i].ev,
+           .id = i,
+           .to = to,
+           .th = current,
+       };
+       if(addblock(&bls[i])) {
+           for(i--; i >= 0; i--)
+               remblock(&bls[i]);
+           return((struct selected){.fd = -1, .ev = -1});
+       }
+    }
+    id = yield();
+    for(i = 0; i < n; i++)
+       remblock(&bls[i]);
+    if(id < 0)
+       return((struct selected){.fd = -1, .ev = -1});
+    return((struct selected){.fd = bls[id].fd, .ev = bls[id].rev});
+}
+
+int block(int fd, int ev, time_t to)
+{
+    struct blocker bl;
+    int rv;
+    
+    bl = (struct blocker) {
+       .fd = fd,
+       .ev = ev,
+       .id = -1,
+       .to = (to > 0)?(time(NULL) + to):0,
+       .th = current,
+    };
+    if(addblock(&bl))
+       return(-1);
+    rv = yield();
+    remblock(&bl);
     return(rv);
 }
 
@@ -211,15 +249,27 @@ int ioloop(void)
                ev = -1;
            for(bl = fdlist[fd]; bl; bl = nbl) {
                nbl = bl->n2;
-               if((ev < 0) || (ev & bl->ev))
-                   resume(bl->th, ev);
+               if((ev < 0) || (ev & bl->ev)) {
+                   if(bl->id < 0) {
+                       resume(bl->th, ev);
+                   } else {
+                       bl->rev = ev;
+                       resume(bl->th, bl->id);
+                   }
+               }
            }
        }
        now = time(NULL);
        for(bl = blockers; bl; bl = nbl) {
            nbl = bl->n;
-           if((bl->to != 0) && (bl->to <= now))
-               resume(bl->th, 0);
+           if((bl->to != 0) && (bl->to <= now)) {
+               if(bl->id < 0) {
+                   resume(bl->th, 0);
+               } else {
+                   bl->rev = 0;
+                   resume(bl->th, bl->id);
+               }
+           }
        }
     }
     for(bl = blockers; bl; bl = bl->n)
index 1235973..e317153 100644 (file)
@@ -37,7 +37,7 @@ static struct blocker *blockers;
 struct blocker {
     struct blocker *n, *p, *n2, *p2;
     int fd, reg;
-    int ev;
+    int ev, rev, id;
     time_t to;
     struct muth *th;
 };
@@ -137,26 +137,19 @@ static void remfd(struct blocker *bl)
     bl->reg = 0;
 }
 
-int block(int fd, int ev, time_t to)
+static int addblock(struct blocker *bl)
 {
-    struct blocker *bl;
-    int rv;
-    
-    omalloc(bl);
-    bl->fd = fd;
-    bl->ev = ev;
-    if(to > 0)
-       bl->to = time(NULL) + to;
-    bl->th = current;
-    if((qfd >= 0) && regfd(bl)) {
-       free(bl);
+    if((qfd >= 0) && regfd(bl))
        return(-1);
-    }
     bl->n = blockers;
     if(blockers)
        blockers->p = bl;
     blockers = bl;
-    rv = yield();
+    return(0);
+}
+
+static void remblock(struct blocker *bl)
+{
     if(bl->n)
        bl->n->p = bl->p;
     if(bl->p)
@@ -164,7 +157,51 @@ int block(int fd, int ev, time_t to)
     if(bl == blockers)
        blockers = bl->n;
     remfd(bl);
-    free(bl);
+}
+
+struct selected mblock(time_t to, int n, struct selected *spec)
+{
+    int i, id;
+    struct blocker bls[n];
+    
+    to = (to > 0)?(time(NULL) + to):0;
+    for(i = 0; i < n; i++) {
+       bls[i] = (struct blocker) {
+           .fd = spec[i].fd,
+           .ev = spec[i].ev,
+           .id = i,
+           .to = to,
+           .th = current,
+       };
+       if(addblock(&bls[i])) {
+           for(i--; i >= 0; i--)
+               remblock(&bls[i]);
+           return((struct selected){.fd = -1, .ev = -1});
+       }
+    }
+    id = yield();
+    for(i = 0; i < n; i++)
+       remblock(&bls[i]);
+    if(id < 0)
+       return((struct selected){.fd = -1, .ev = -1});
+    return((struct selected){.fd = bls[id].fd, .ev = bls[id].rev});
+}
+
+int block(int fd, int ev, time_t to)
+{
+    struct blocker bl;
+    int rv;
+    
+    bl = (struct blocker) {
+       .fd = fd,
+       .ev = ev,
+       .id = -1,
+       .to = (to > 0)?(time(NULL) + to):0,
+       .th = current,
+    };
+    addblock(&bl);
+    rv = yield();
+    remblock(&bl);
     return(rv);
 }
 
@@ -214,15 +251,27 @@ int ioloop(void)
            ev = (evs[i].filter == EVFILT_READ)?EV_READ:EV_WRITE;
            for(bl = fdlist[fd]; bl; bl = nbl) {
                nbl = bl->n2;
-               if(ev & bl->ev)
-                   resume(bl->th, ev);
+               if(ev & bl->ev) {
+                   if(bl->id < 0) {
+                       resume(bl->th, ev);
+                   } else {
+                       bl->rev = ev;
+                       resume(bl->th, bl->id);
+                   }
+               }
            }
        }
        now = time(NULL);
        for(bl = blockers; bl; bl = nbl) {
            nbl = bl->n;
-           if((bl->to != 0) && (bl->to <= now))
-               resume(bl->th, 0);
+           if((bl->to != 0) && (bl->to <= now)) {
+               if(bl->id < 0) {
+                   resume(bl->th, 0);
+               } else {
+                   bl->rev = 0;
+                   resume(bl->th, bl->id);
+               }
+           }
        }
     }
     for(bl = blockers; bl; bl = bl->n)
index 26e6785..6e9a767 100644 (file)
@@ -37,39 +37,73 @@ static int exitstatus;
 struct blocker {
     struct blocker *n, *p;
     int fd;
-    int ev;
+    int ev, rev, id;
     time_t to;
     struct muth *th;
 };
 
-int block(int fd, int ev, time_t to)
+static void addblock(struct blocker *bl)
 {
-    struct blocker *bl;
-    int rv;
-    
-    if(fd >= FD_SETSIZE) {
-       flog(LOG_ERR, "tried to use more file descriptors than select() can handle: fd %i", fd);
-       errno = EMFILE;
-       return(-1);
-    }
-    omalloc(bl);
-    bl->fd = fd;
-    bl->ev = ev;
-    if(to > 0)
-       bl->to = time(NULL) + to;
-    bl->th = current;
     bl->n = blockers;
     if(blockers)
        blockers->p = bl;
     blockers = bl;
-    rv = yield();
+}
+
+static void remblock(struct blocker *bl)
+{
     if(bl->n)
        bl->n->p = bl->p;
     if(bl->p)
        bl->p->n = bl->n;
     if(bl == blockers)
        blockers = bl->n;
-    free(bl);
+}
+
+struct selected mblock(time_t to, int n, struct selected *spec)
+{
+    int i, id;
+    struct blocker bls[n];
+    
+    to = (to > 0)?(time(NULL) + to):0;
+    for(i = 0; i < n; i++) {
+       bls[i] = (struct blocker){
+           .fd = spec[i].fd,
+           .ev = spec[i].ev,
+           .id = i,
+           .to = to,
+           .th = current,
+       };
+       addblock(&bls[i]);
+    }
+    id = yield();
+    for(i = 0; i < n; i++)
+       remblock(&bls[i]);
+    if(id < 0)
+       return((struct selected){.fd = -1, .ev = -1});
+    return((struct selected){.fd = bls[id].fd, .ev = bls[id].rev});
+}
+
+int block(int fd, int ev, time_t to)
+{
+    struct blocker bl;
+    int rv;
+    
+    if(fd >= FD_SETSIZE) {
+       flog(LOG_ERR, "tried to use more file descriptors than select() can handle: fd %i", fd);
+       errno = EMFILE;
+       return(-1);
+    }
+    bl = (struct blocker) {
+       .fd = fd,
+       .ev = ev,
+       .id = -1,
+       .to = (to > 0)?(time(NULL) + to):0,
+       .th = current,
+    };
+    addblock(&bl);
+    rv = yield();
+    remblock(&bl);
     return(rv);
 }
 
@@ -125,10 +159,21 @@ int ioloop(void)
                    ev |= EV_WRITE;
                if(FD_ISSET(bl->fd, &efds))
                    ev = -1;
-               if((ev < 0) || (ev & bl->ev))
-                   resume(bl->th, ev);
-               else if((bl->to != 0) && (bl->to <= now))
-                   resume(bl->th, 0);
+               if((ev < 0) || (ev & bl->ev)) {
+                   if(bl->id < 0) {
+                       resume(bl->th, ev);
+                   } else {
+                       bl->rev = ev;
+                       resume(bl->th, bl->id);
+                   }
+               } else if((bl->to != 0) && (bl->to <= now)) {
+                   if(bl->id < 0) {
+                       resume(bl->th, 0);
+                   } else {
+                       bl->rev = 0;
+                       resume(bl->th, bl->id);
+                   }
+               }
            }
        }
     }
index d7f36ac..b911f72 100644 (file)
 #include <utils.h>
 #include <mt.h>
 #include <mtio.h>
+#include <bufio.h>
+
+static ssize_t mtrecv(struct stdiofd *d, void *buf, size_t len)
+{
+    struct msghdr msg;
+    char cbuf[512];
+    struct cmsghdr *cmsg;
+    struct iovec bufvec;
+    socklen_t clen;
+    ssize_t ret;
+    int i, *fds;
+    
+    msg = (struct msghdr){};
+    msg.msg_iov = &bufvec;
+    msg.msg_iovlen = 1;
+    bufvec.iov_base = buf;
+    bufvec.iov_len = len;
+    msg.msg_control = cbuf;
+    msg.msg_controllen = sizeof(cbuf);
+    if((ret = recvmsg(d->fd, &msg, MSG_DONTWAIT)) < 0)
+       return(ret);
+    for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+       if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS)) {
+           fds = (int *)CMSG_DATA(cmsg);
+           clen = (cmsg->cmsg_len - ((char *)fds - (char *)cmsg)) / sizeof(*fds);
+           for(i = 0; i < clen; i++) {
+               if(d->rights < 0)
+                   d->rights = fds[i];
+               else
+                   close(fds[i]);
+           }
+       }
+    }
+    return(ret);
+}
 
 static ssize_t mtread(void *cookie, void *buf, size_t len)
 {
@@ -39,7 +74,10 @@ static ssize_t mtread(void *cookie, void *buf, size_t len)
     ssize_t ret;
     
     while(1) {
-       ret = read(d->fd, buf, len);
+       if(d->sock)
+           ret = mtrecv(d, buf, len);
+       else
+           ret = read(d->fd, buf, len);
        if((ret < 0) && (errno == EAGAIN)) {
            ev = block(d->fd, EV_READ, d->timeout);
            if(ev < 0) {
@@ -57,6 +95,39 @@ static ssize_t mtread(void *cookie, void *buf, size_t len)
     }
 }
 
+static ssize_t mtsend(struct stdiofd *d, const void *buf, size_t len)
+{
+    struct msghdr msg;
+    struct cmsghdr *cmsg;
+    char cbuf[CMSG_SPACE(sizeof(int))];
+    struct iovec bufvec;
+    ssize_t ret;
+    int cr;
+    
+    msg = (struct msghdr){};
+    msg.msg_iov = &bufvec;
+    msg.msg_iovlen = 1;
+    bufvec.iov_base = (void *)buf;
+    bufvec.iov_len = len;
+    cr = -1;
+    if(d->sendrights >= 0) {
+       msg.msg_control = cbuf;
+       msg.msg_controllen = sizeof(cbuf);
+       cmsg = CMSG_FIRSTHDR(&msg);
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+       *((int *)CMSG_DATA(cmsg)) = d->sendrights;
+       cr = d->sendrights;
+       d->sendrights = -1;
+       msg.msg_controllen = cmsg->cmsg_len;
+    }
+    ret = sendmsg(d->fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
+    if(cr >= 0)
+       close(cr);
+    return(ret);
+}
+
 static ssize_t mtwrite(void *cookie, const void *buf, size_t len)
 {
     struct stdiofd *d = cookie;
@@ -65,7 +136,7 @@ static ssize_t mtwrite(void *cookie, const void *buf, size_t len)
     
     while(1) {
        if(d->sock)
-           ret = send(d->fd, buf, len, MSG_DONTWAIT | MSG_NOSIGNAL);
+           ret = mtsend(d, buf, len);
        else
            ret = write(d->fd, buf, len);
        if((ret < 0) && (errno == EAGAIN)) {
@@ -88,6 +159,10 @@ static int mtclose(void *cookie)
     struct stdiofd *d = cookie;
     
     close(d->fd);
+    if(d->rights >= 0)
+       close(d->rights);
+    if(d->sendrights >= 0)
+       close(d->sendrights);
     free(d);
     return(0);
 }
@@ -111,6 +186,7 @@ FILE *mtstdopen(int fd, int issock, int timeout, char *mode, struct stdiofd **in
     d->fd = fd;
     d->sock = issock;
     d->timeout = timeout;
+    d->rights = d->sendrights = -1;
     if(!(ret = funstdio(d, r?mtread:NULL, w?mtwrite:NULL, NULL, mtclose))) {
        free(d);
        return(NULL);
@@ -121,6 +197,35 @@ FILE *mtstdopen(int fd, int issock, int timeout, char *mode, struct stdiofd **in
     return(ret);
 }
 
+struct bufio *mtbioopen(int fd, int issock, int timeout, char *mode, struct stdiofd **infop)
+{
+    static struct bufioops ops = {
+       .read = mtread, .write = mtwrite, .close = mtclose,
+    };
+    struct stdiofd *d;
+    struct bufio *ret;
+    
+    if(!strcmp(mode, "r")) {
+    } else if(!strcmp(mode, "w")) {
+    } else if(!strcmp(mode, "r+")) {
+    } else {
+       return(NULL);
+    }
+    omalloc(d);
+    d->fd = fd;
+    d->sock = issock;
+    d->timeout = timeout;
+    d->rights = d->sendrights = -1;
+    if(!(ret = bioopen(d, &ops))) {
+       free(d);
+       return(NULL);
+    }
+    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+    if(infop)
+       *infop = d;
+    return(ret);
+}
+
 struct pipe {
     struct charbuf data;
     size_t bufmax;
index 75928eb..ffb57da 100644 (file)
@@ -10,12 +10,19 @@ struct stdiofd {
     int fd;
     int sock;
     int timeout;
+    int rights, sendrights;
 };
 
+struct selected {
+    int fd, ev;
+};
+
+struct selected mblock(time_t to, int n, struct selected *spec);
 int block(int fd, int ev, time_t to);
 int ioloop(void);
 void exitioloop(int status);
 FILE *mtstdopen(int fd, int issock, int timeout, char *mode, struct stdiofd **infop);
+struct bufio *mtbioopen(int fd, int issock, int timeout, char *mode, struct stdiofd **infop);
 void mtiopipe(FILE **read, FILE **write);
 
 #endif
index ed5aeba..074e7df 100644 (file)
--- a/lib/req.c
+++ b/lib/req.c
@@ -32,6 +32,7 @@
 #include <log.h>
 #include <req.h>
 #include <proc.h>
+#include <bufio.h>
 
 struct hthead *mkreq(char *method, char *url, char *ver)
 {
@@ -164,6 +165,68 @@ fail:
     return(-1);
 }
 
+int parseheadersb(struct hthead *head, struct bufio *in)
+{
+    int c, state;
+    struct charbuf name, val;
+    size_t tsz;
+    
+    bufinit(name);
+    bufinit(val);
+    state = 0;
+    tsz = 0;
+    while(1) {
+       c = biogetc(in);
+       if(++tsz >= 65536)
+           goto fail;
+    again:
+       if(state == 0) {
+           if(c == '\r') {
+           } else if(c == '\n') {
+               break;
+           } else if(c == EOF) {
+               goto fail;
+           } else {
+               state = 1;
+               goto again;
+           }
+       } else if(state == 1) {
+           if(c == ':') {
+               trim(&name);
+               bufadd(name, 0);
+               state = 2;
+           } else if(c == '\r') {
+           } else if(c == '\n') {
+               goto fail;
+           } else if(c == EOF) {
+               goto fail;
+           } else {
+               bufadd(name, c);
+           }
+       } else if(state == 2) {
+           if(c == '\r') {
+           } else if(c == '\n') {
+               trim(&val);
+               bufadd(val, 0);
+               headappheader(head, name.b, val.b);
+               buffree(name);
+               buffree(val);
+               state = 0;
+           } else if(c == EOF) {
+               goto fail;
+           } else {
+               bufadd(val, c);
+           }
+       }
+    }
+    return(0);
+    
+fail:
+    buffree(name);
+    buffree(val);
+    return(-1);
+}
+
 struct hthead *parseresponse(FILE *in)
 {
     struct hthead *req;
@@ -230,6 +293,72 @@ out:
     return(req);
 }
 
+struct hthead *parseresponseb(struct bufio *in)
+{
+    struct hthead *req;
+    int code;
+    struct charbuf ver, msg;
+    int c;
+    
+    req = NULL;
+    bufinit(ver);
+    bufinit(msg);
+    code = 0;
+    while(1) {
+       c = biogetc(in);
+       if(c == ' ') {
+           break;
+       } else if((c == EOF) || (c < 32) || (c >= 128)) {
+           goto fail;
+       } else {
+           bufadd(ver, c);
+           if(ver.d >= 128)
+               goto fail;
+       }
+    }
+    while(1) {
+       c = biogetc(in);
+       if(c == ' ') {
+           break;
+       } else if((c == EOF) || (c < '0') || (c > '9')) {
+           goto fail;
+       } else {
+           code = (code * 10) + (c - '0');
+           if(code >= 10000)
+               goto fail;
+       }
+    }
+    while(1) {
+       c = biogetc(in);
+       if(c == 10) {
+           break;
+       } else if(c == 13) {
+       } else if((c == EOF) || (c < 32)) {
+           goto fail;
+       } else {
+           bufadd(msg, c);
+           if(msg.d >= 512)
+               goto fail;
+       }
+    }
+    bufadd(msg, 0);
+    bufadd(ver, 0);
+    req = mkresp(code, msg.b, ver.b);
+    if(parseheadersb(req, in))
+       goto fail;
+    goto out;
+    
+fail:
+    if(req != NULL) {
+       freehthead(req);
+       req = NULL;
+    }
+out:
+    buffree(msg);
+    buffree(ver);
+    return(req);
+}
+
 void replrest(struct hthead *head, char *rest)
 {
     char *tmp;
@@ -290,6 +419,19 @@ int writeresp(FILE *out, struct hthead *resp)
     return(0);
 }
 
+int writerespb(struct bufio *out, struct hthead *resp)
+{
+    int i;
+    
+    if(bioprintf(out, "%s %i %s\r\n", resp->ver, resp->code, resp->msg) < 0)
+       return(-1);
+    for(i = 0; i < resp->noheaders; i++) {
+       if(bioprintf(out, "%s: %s\r\n", resp->headers[i][0], resp->headers[i][1]) < 0)
+           return(-1);
+    }
+    return(0);
+}
+
 int sendreq2(int sock, struct hthead *req, int fd, int flags)
 {
     int ret, i;
index 054d3c1..9ae60ab 100644 (file)
--- a/lib/req.h
+++ b/lib/req.h
@@ -3,6 +3,8 @@
 
 #include <stdio.h>
 
+struct bufio;
+
 struct hthead {
     char *method, *url, *ver, *msg;
     int code;
@@ -23,8 +25,11 @@ int sendreq(int sock, struct hthead *req, int fd);
 int recvreq(int sock, struct hthead **reqp);
 void replrest(struct hthead *head, char *rest);
 int parseheaders(struct hthead *head, FILE *in);
+int parseheadersb(struct hthead *head, struct bufio *in);
 struct hthead *parseresponse(FILE *in);
+struct hthead *parseresponseb(struct bufio *in);
 int writeresp(FILE *out, struct hthead *resp);
+int writerespb(struct bufio *out, struct hthead *resp);
 char *unquoteurl(char *in);
 
 #endif
index a63362d..fa0b8b5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python3
 
 import sys, os, getopt, socket, logging, time, locale, collections, signal
-import ashd.util, ashd.serve
+import ashd.util, ashd.serve, ashd.htlib
 try:
     import pdm.srv
 except:
@@ -157,6 +157,7 @@ class request(ashd.serve.wsgirequest):
     def __init__(self, *, bkreq, **kw):
         super().__init__(**kw)
         self.bkreq = bkreq.dup()
+        self.sendrights = None
 
     def mkenv(self):
         return mkenv(self.bkreq)
@@ -168,6 +169,13 @@ class request(ashd.serve.wsgirequest):
         return self.bkreq.bsk.fileno()
 
     def writehead(self, status, headers):
+        headers = list(headers)
+        for header in headers:
+            nm, val = header
+            if nm.lower() == "x-ash-send-rights":
+                self.sendrights = val
+                headers.remove(header)
+                break
         w = self.buffer.extend
         w(b"HTTP/1.1 " + recode(status) + b"\n")
         for nm, val in headers:
@@ -176,13 +184,22 @@ class request(ashd.serve.wsgirequest):
 
     def flush(self):
         try:
-            ret = self.bkreq.bsk.send(self.buffer, socket.MSG_DONTWAIT)
+            if self.sendrights is not None:
+                ret = ashd.htlib.sendfd(self.bkreq.bsk.fileno(), self.sendrights.fileno(), self.buffer)
+                self.sendrights.close()
+                self.sendrights = None
+            else:
+                ret = self.bkreq.bsk.send(self.buffer, socket.MSG_DONTWAIT)
             self.buffer[:ret] = b""
         except IOError:
             raise ashd.serve.closed()
 
     def close(self):
-        self.bkreq.close()
+        try:
+            self.bkreq.close()
+        finally:
+            if self.sendrights is not None:
+                self.sendrights.close()
 
 def handle(req):
     reqhandler.handle(request(bkreq=req, handler=reqhandler))
index a3894bf..af43373 100644 (file)
@@ -39,6 +39,7 @@
 #include <proc.h>
 #include <mt.h>
 #include <mtio.h>
+#include <bufio.h>
 
 #define DEFFORMAT "%{%Y-%m-%d %H:%M:%S}t %m %u %A \"%G\""
 
@@ -215,20 +216,21 @@ static void serve(struct hthead *req, int fd)
     logreq(&data);
 }
 
-static int passdata(FILE *in, FILE *out, off_t *passed)
+static int passdata(struct bufio *in, struct bufio *out, off_t *passed)
 {
-    size_t read;
+    ssize_t read;
     off_t total;
-    char buf[8192];
     
     total = 0;
-    while(!feof(in)) {
-       read = fread(buf, 1, sizeof(buf), in);
-       if(ferror(in))
-           return(-1);
-       if(fwrite(buf, 1, read, out) != read)
+    while(!bioeof(in)) {
+       if((read = biordata(in)) > 0) {
+           if((read = biowritesome(out, in->rbuf.b + in->rh, read)) < 0)
+               return(-1);
+           in->rh += read;
+           total += read;
+       }
+       if(biorspace(in) && (biofillsome(in) < 0))
            return(-1);
-       total += read;
     }
     if(passed)
        *passed = total;
@@ -241,7 +243,8 @@ static void filterreq(struct muth *mt, va_list args)
     vavar(int, fd);
     int pfds[2];
     struct hthead *resp;
-    FILE *cl, *hd;
+    struct bufio *cl, *hd;
+    struct stdiofd *cli, *hdi;
     struct logdata data;
     
     hd = NULL;
@@ -249,10 +252,10 @@ static void filterreq(struct muth *mt, va_list args)
     data = defdata;
     data.req = req;
     gettimeofday(&data.start, NULL);
-    cl = mtstdopen(fd, 1, 600, "r+", NULL);
+    cl = mtbioopen(fd, 1, 600, "r+", &cli);
     if(socketpair(PF_UNIX, SOCK_STREAM, 0, pfds))
        goto out;
-    hd = mtstdopen(pfds[1], 1, 600, "r+", NULL);
+    hd = mtbioopen(pfds[1], 1, 600, "r+", &hdi);
     if(sendreq(ch, req, pfds[0])) {
        close(pfds[0]);
        goto out;
@@ -261,14 +264,16 @@ static void filterreq(struct muth *mt, va_list args)
     
     if(passdata(cl, hd, &data.bytesin))
        goto out;
-    if(fflush(hd))
+    if(bioflush(hd))
        goto out;
     shutdown(pfds[1], SHUT_WR);
-    if((resp = parseresponse(hd)) == NULL)
+    if((resp = parseresponseb(hd)) == NULL)
        goto out;
+    cli->sendrights = hdi->rights;
+    hdi->rights = -1;
     data.resp = resp;
-    writeresp(cl, resp);
-    fprintf(cl, "\r\n");
+    writerespb(cl, resp);
+    bioprintf(cl, "\r\n");
     if(passdata(hd, cl, &data.bytesout))
        goto out;
     gettimeofday(&data.end, NULL);
@@ -279,9 +284,9 @@ out:
     freehthead(req);
     if(resp != NULL)
        freehthead(resp);
-    fclose(cl);
+    bioclose(cl);
     if(hd != NULL)
-       fclose(hd);
+       bioclose(hd);
 }
 
 static void sighandler(int sig)
index 92445d7..a738e25 100644 (file)
@@ -35,6 +35,7 @@
 #include <log.h>
 #include <req.h>
 #include <proc.h>
+#include <bufio.h>
 
 #include "htparser.h"
 
@@ -60,7 +61,7 @@ static void trimx(struct hthead *req)
     }
 }
 
-static struct hthead *parsereq(FILE *in)
+static struct hthead *parsereq(struct bufio *in)
 {
     struct hthead *req;
     struct charbuf method, url, ver;
@@ -71,7 +72,7 @@ static struct hthead *parsereq(FILE *in)
     bufinit(url);
     bufinit(ver);
     while(1) {
-       c = getc(in);
+       c = biogetc(in);
        if(c == ' ') {
            break;
        } else if((c == EOF) || (c < 32) || (c >= 128)) {
@@ -83,7 +84,7 @@ static struct hthead *parsereq(FILE *in)
        }
     }
     while(1) {
-       c = getc(in);
+       c = biogetc(in);
        if(c == ' ') {
            break;
        } else if((c == EOF) || (c < 32)) {
@@ -95,7 +96,7 @@ static struct hthead *parsereq(FILE *in)
        }
     }
     while(1) {
-       c = getc(in);
+       c = biogetc(in);
        if(c == 10) {
            break;
        } else if(c == 13) {
@@ -111,7 +112,7 @@ static struct hthead *parsereq(FILE *in)
     bufadd(url, 0);
     bufadd(ver, 0);
     req = mkreq(method.b, url.b, ver.b);
-    if(parseheaders(req, in))
+    if(parseheadersb(req, in))
        goto fail;
     trimx(req);
     goto out;
@@ -128,38 +129,37 @@ out:
     return(req);
 }
 
-static off_t passdata(FILE *in, FILE *out, off_t max)
+static off_t passdata(struct bufio *in, struct bufio *out, off_t max)
 {
-    size_t read;
+    ssize_t read;
     off_t total;
-    char buf[8192];
     
     total = 0;
-    while(!feof(in) && ((max < 0) || (total < max))) {
-       read = sizeof(buf);
-       if(max >= 0)
-           read = min(max - total, read);
-       read = fread(buf, 1, read, in);
-       if(ferror(in))
-           return(-1);
-       if(fwrite(buf, 1, read, out) != read)
+    while(!bioeof(in) && ((max < 0) || (total < max))) {
+       if((read = biordata(in)) > 0) {
+           if(max >= 0)
+               read = min(max - total, read);
+           if((read = biowritesome(out, in->rbuf.b + in->rh, read)) < 0)
+               return(-1);
+           in->rh += read;
+           total += read;
+       }
+       if(biorspace(in) && ((max < 0) || (biordata(in) < max - total)) && (biofillsome(in) < 0))
            return(-1);
-       total += read;
     }
     return(total);
 }
 
-static int recvchunks(FILE *in, FILE *out)
+static int recvchunks(struct bufio *in, struct bufio *out)
 {
-    char buf[8192];
-    size_t read, chlen;
+    ssize_t read, chlen;
     int c, r;
     
     while(1) {
        chlen = 0;
        r = 0;
        while(1) {
-           c = getc(in);
+           c = biogetc(in);
            if(c == 10) {
                if(!r)
                    return(-1);
@@ -185,37 +185,43 @@ static int recvchunks(FILE *in, FILE *out)
        if(chlen == 0)
            break;
        while(chlen > 0) {
-           read = fread(buf, 1, min(sizeof(buf), chlen), in);
-           if(feof(in) || ferror(in))
-               return(-1);
-           if(fwrite(buf, 1, read, out) != read)
+           if((read = biordata(in)) > 0) {
+               if((read = biowritesome(out, in->rbuf.b + in->rh, min(read, chlen))) < 0)
+                   return(-1);
+               in->rh += read;
+               chlen -= read;
+           }
+           if(biorspace(in) && (biordata(in) < chlen) && (biofillsome(in) <= 0))
                return(-1);
-           chlen -= read;
        }
-       if((getc(in) != 13) || (getc(in) != 10))
+       if((biogetc(in) != 13) || (biogetc(in) != 10))
            return(-1);
     }
     /* XXX: Technically, there may be trailers to be read, but that's
      * just about as likely as chunk extensions. */
-    if((getc(in) != 13) || (getc(in) != 10))
+    if((biogetc(in) != 13) || (biogetc(in) != 10))
        return(-1);
     return(0);
 }
 
-static int passchunks(FILE *in, FILE *out)
+static int passchunks(struct bufio *in, struct bufio *out)
 {
-    char buf[8192];
     size_t read;
     
-    do {
-       read = fread(buf, 1, sizeof(buf), in);
-       if(ferror(in))
-           return(-1);
-       fprintf(out, "%zx\r\n", read);
-       if(fwrite(buf, 1, read, out) != read)
+    while(!bioeof(in)) {
+       if((read = biordata(in)) > 0) {
+           bioprintf(out, "%zx\r\n", read);
+           if(biowrite(out, in->rbuf.b + in->rh, read) != read)
+               return(-1);
+           in->rh += read;
+           bioprintf(out, "\r\n");
+           if(bioflush(out) < 0)
+               return(-1);
+       }
+       if(biorspace(in) && (biofillsome(in) < 0))
            return(-1);
-       fprintf(out, "\r\n");
-    } while(read > 0);
+    }
+    bioprintf(out, "0\r\n\r\n");
     return(0);
 }
 
@@ -299,19 +305,63 @@ done:
     return(ret);
 }
 
-void serve(FILE *in, struct conn *conn)
+static void passduplex(struct bufio *a, int afd, struct bufio *b, int bfd)
+{
+    struct selected pfd[4], sel;
+    struct bufio *sio;
+    int n, ev;
+    
+    while(!bioeof(a) && !bioeof(b)) {
+       biocopybuf(b, a);
+       biocopybuf(a, b);
+       n = 0;
+       if(!a->eof) {
+           ev = 0;
+           if(biorspace(a))
+               ev |= EV_READ;
+           if(biowdata(a))
+               ev |= EV_WRITE;
+           if(ev)
+               pfd[n++] = (struct selected){.fd = afd, .ev = ev};
+       }
+       if(!b->eof) {
+           ev = 0;
+           if(!b->eof && biorspace(b))
+               ev |= EV_READ;
+           if(biowdata(b))
+               ev |= EV_WRITE;
+           if(ev)
+               pfd[n++] = (struct selected){.fd = bfd, .ev = ev};
+       }
+       sel = mblock(600, n, pfd);
+       if(sel.fd == afd)
+           sio = a;
+       else if(sel.fd == bfd)
+           sio = b;
+       else
+           break;
+       if((sel.ev & EV_READ) && (biofillsome(sio) < 0))
+           break;
+       if((sel.ev & EV_WRITE) && (bioflushsome(sio) < 0))
+           break;
+    }
+}
+
+void serve(struct bufio *in, int infd, struct conn *conn)
 {
     int pfds[2];
-    FILE *out;
+    struct bufio *out, *dout;
+    struct stdiofd *outi;
     struct hthead *req, *resp;
     char *hd, *id;
     off_t dlen;
-    int keep;
+    int keep, duplex;
     
     id = connid();
     out = NULL;
     req = resp = NULL;
     while(plex >= 0) {
+       bioflush(in);
        if((req = parsereq(in)) == NULL)
            break;
        if(!canonreq(req))
@@ -328,7 +378,7 @@ void serve(FILE *in, struct conn *conn)
        if(sendreq(plex, req, pfds[0]))
            break;
        close(pfds[0]);
-       out = mtstdopen(pfds[1], 1, 600, "r+", NULL);
+       out = mtbioopen(pfds[1], 1, 600, "r+", &outi);
 
        if(getheader(req, "content-type") != NULL) {
            if((hd = getheader(req, "content-length")) != NULL) {
@@ -345,34 +395,46 @@ void serve(FILE *in, struct conn *conn)
                headrmheader(req, "content-type");
            }
        }
-       if(fflush(out))
+       if(bioflush(out))
            break;
        /* Make sure to send EOF */
        shutdown(pfds[1], SHUT_WR);
        
-       if((resp = parseresponse(out)) == NULL)
+       if((resp = parseresponseb(out)) == NULL)
            break;
        replstr(&resp->ver, req->ver);
        
        if(!getheader(resp, "server"))
            headappheader(resp, "Server", sprintf3("ashd/%s", VERSION));
+       duplex = hasheader(resp, "x-ash-switch", "duplex");
+       trimx(resp);
 
-       if(!strcasecmp(req->ver, "HTTP/1.0")) {
+       if(duplex) {
+           if(outi->rights < 0)
+               break;
+           writerespb(in, resp);
+           bioprintf(in, "\r\n");
+           dout = mtbioopen(outi->rights, 1, 600, "r+", NULL);
+           passduplex(in, infd, dout, outi->rights);
+           outi->rights = -1;
+           bioclose(dout);
+           break;
+       } else if(!strcasecmp(req->ver, "HTTP/1.0")) {
            if(!strcasecmp(req->method, "head")) {
                keep = http10keep(req, resp);
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
            } else if((hd = getheader(resp, "content-length")) != NULL) {
                keep = http10keep(req, resp);
                dlen = atoo(hd);
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
                if(passdata(out, in, dlen) != dlen)
                    break;
            } else {
                headrmheader(resp, "connection");
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
                passdata(out, in, -1);
                break;
            }
@@ -380,23 +442,23 @@ void serve(FILE *in, struct conn *conn)
                break;
        } else if(!strcasecmp(req->ver, "HTTP/1.1")) {
            if(!strcasecmp(req->method, "head")) {
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
            } else if((hd = getheader(resp, "content-length")) != NULL) {
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
                dlen = atoo(hd);
                if(passdata(out, in, dlen) != dlen)
                    break;
            } else if(!getheader(resp, "transfer-encoding")) {
                headappheader(resp, "Transfer-Encoding", "chunked");
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
                if(passchunks(out, in))
                    break;
            } else {
-               writeresp(in, resp);
-               fprintf(in, "\r\n");
+               writerespb(in, resp);
+               bioprintf(in, "\r\n");
                passdata(out, in, -1);
                break;
            }
@@ -406,7 +468,7 @@ void serve(FILE *in, struct conn *conn)
            break;
        }
 
-       fclose(out);
+       bioclose(out);
        out = NULL;
        freehthead(req);
        freehthead(resp);
@@ -414,12 +476,12 @@ void serve(FILE *in, struct conn *conn)
     }
     
     if(out != NULL)
-       fclose(out);
+       bioclose(out);
     if(req != NULL)
        freehthead(req);
     if(resp != NULL)
        freehthead(resp);
-    fclose(in);
+    bioclose(in);
     free(id);
 }
 
index 7bd60a0..d9f014d 100644 (file)
@@ -11,7 +11,7 @@ struct mtbuf {
     size_t s, d;
 };
 
-void serve(FILE *in, struct conn *conn);
+void serve(struct bufio *in, int infd, struct conn *conn);
 
 int listensock4(int port);
 int listensock6(int port);
index 1d3e2e7..56fc81c 100644 (file)
@@ -150,19 +150,19 @@ void servetcp(struct muth *muth, va_list args)
     vavar(int, fd);
     vavar(struct sockaddr_storage, name);
     vavar(struct tcpport *, stcp);
-    FILE *in;
+    struct bufio *in;
     struct conn conn;
     struct tcpconn tcp;
     
     memset(&conn, 0, sizeof(conn));
     memset(&tcp, 0, sizeof(tcp));
-    in = mtstdopen(fd, 1, 60, "r+", NULL);
+    in = mtbioopen(fd, 1, 60, "r+", NULL);
     conn.pdata = &tcp;
     conn.initreq = initreq;
     tcp.fd = fd;
     tcp.name = name;
     tcp.port = stcp;
-    serve(in, &conn);
+    serve(in, fd, &conn);
 }
 
 static void listenloop(struct muth *muth, va_list args)
index a181add..7aa1df0 100644 (file)
@@ -34,6 +34,7 @@
 #include <mtio.h>
 #include <req.h>
 #include <log.h>
+#include <bufio.h>
 
 #include "htparser.h"
 
@@ -188,7 +189,7 @@ static int tlsblock(int fd, gnutls_session_t sess, time_t to)
        return(block(fd, EV_READ, to));
 }
 
-static ssize_t sslread(void *cookie, char *buf, size_t len)
+static ssize_t sslread(void *cookie, void *buf, size_t len)
 {
     struct sslconn *ssl = cookie;
     ssize_t xf;
@@ -217,7 +218,7 @@ static ssize_t sslread(void *cookie, char *buf, size_t len)
     return(xf);
 }
 
-static ssize_t sslwrite(void *cookie, const char *buf, size_t len)
+static ssize_t sslwrite(void *cookie, const void *buf, size_t len)
 {
     struct sslconn *ssl = cookie;
     int ret;
@@ -255,7 +256,7 @@ static int sslclose(void *cookie)
     return(0);
 }
 
-static cookie_io_functions_t iofuns = {
+static struct bufioops iofuns = {
     .read = sslread,
     .write = sslwrite,
     .close = sslclose,
@@ -289,7 +290,6 @@ static void servessl(struct muth *muth, va_list args)
     struct sslconn ssl;
     gnutls_session_t sess;
     int ret;
-    FILE *in;
     
     int setcreds(gnutls_session_t sess)
     {
@@ -344,8 +344,7 @@ static void servessl(struct muth *muth, va_list args)
     ssl.name = name;
     ssl.sess = sess;
     bufinit(ssl.in);
-    in = fopencookie(&ssl, "r+", iofuns);
-    serve(in, &conn);
+    serve(bioopen(&ssl, &iofuns), fd, &conn);
     
 out:
     gnutls_deinit(sess);