#include "htparser.h"
static int plex;
-static char *pidfile = NULL;
static int daemonize, usesyslog;
struct mtbuf listeners;
static int recvchunks(struct bufio *in, struct bufio *out)
{
- size_t read, chlen;
+ ssize_t read, chlen;
int c, r;
while(1) {
return(ret);
}
-void serve(struct bufio *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};
+ }
+ if((sel = mblock(600, n, pfd)).ev == 0)
+ break;
+ 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];
- struct bufio *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;
if(sendreq(plex, req, pfds[0]))
break;
close(pfds[0]);
- out = mtbioopen(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) {
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);
writerespb(in, resp);
/* XXX: It would be nice to decentralize this, but, meh... */
if(!strcmp(nm, "plain")) {
handleplain(pars.d, pars.b, vals.b);
-#ifdef HAVE_GNUTLS
+#if defined HAVE_GNUTLS
} else if(!strcmp(nm, "ssl")) {
handlegnussl(pars.d, pars.b, vals.b);
+#elif defined HAVE_OPENSSL
+ } else if(!strcmp(nm, "ssl")) {
+ handleossl(pars.d, pars.b, vals.b);
#endif
} else {
flog(LOG_ERR, "htparser: unknown port handler `%s'", nm);
{
int c, d;
int i, s1;
- char *root;
+ char *root, *pidfile, *pidtmp;
FILE *pidout;
struct passwd *pwent;
daemonize = usesyslog = 0;
- root = NULL;
+ root = pidfile = NULL;
pwent = NULL;
while((c = getopt(argc, argv, "+hSfu:r:p:")) >= 0) {
switch(c) {
usesyslog = 1;
break;
case 'u':
- if((pwent = getpwnam(optarg)) == NULL) {
+ if(optarg[0] && ((pwent = getpwnam(optarg)) == NULL)) {
flog(LOG_ERR, "could not find user %s", optarg);
exit(1);
}
break;
case 'r':
- root = optarg;
+ root = optarg[0] ? optarg : NULL;
break;
case 'p':
- pidfile = optarg;
+ pidfile = optarg[0] ? optarg : NULL;
break;
default:
usage(stderr);
bufadd(listeners, mustart(plexwatch, plex));
pidout = NULL;
if(pidfile != NULL) {
- if((pidout = fopen(pidfile, "w")) == NULL) {
- flog(LOG_ERR, "could not open %s for writing: %s", pidfile, strerror(errno));
+ pidtmp = sprintf3("%s.new", pidfile);
+ if((pidout = fopen(pidtmp, "w")) == NULL) {
+ flog(LOG_ERR, "could not open %s for writing: %s", pidtmp, strerror(errno));
+ return(1);
+ }
+ if(rename(pidtmp, pidfile)) {
+ flog(LOG_ERR, "could not overwrite %s: %s", pidfile, strerror(errno));
+ unlink(pidtmp);
return(1);
}
}
}
if(pidout != NULL) {
fprintf(pidout, "%i\n", getpid());
- fclose(pidout);
+ fflush(pidout);
}
d = 0;
while(!d) {
while(listeners.d > 0)
resume(listeners.b[0], 0);
flog(LOG_INFO, "no longer listening");
+ if(pidout != NULL) {
+ putc('\n', pidout);
+ fflush(pidout);
+ }
} else {
d = 1;
}
break;
}
}
+ if(pidout != NULL)
+ ftruncate(fileno(pidout), 0);
return(0);
}