You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
3.5 KiB
136 lines
3.5 KiB
#include "fcgi-debug.h"
|
|
|
|
void stream_init(server *srv, stream *s1, stream *s2, int fd1, int fd2, ev_io_cb cb1, ev_io_cb cb2, void* data) {
|
|
UNUSED(srv);
|
|
fd_init(fd1);
|
|
fd_init(fd2);
|
|
s1->other = s2;
|
|
s2->other = s1;
|
|
s1->fd = fd1;
|
|
s2->fd = fd2;
|
|
ev_io *w1 = &s1->watcher, *w2 = &s2->watcher;
|
|
ev_io_init(w1, cb1, fd1, 0);
|
|
ev_io_init(w2, cb2, fd2, 0);
|
|
w1->data = data;
|
|
w2->data = data;
|
|
s1->buffer = g_string_sized_new(0);
|
|
s2->buffer = g_string_sized_new(0);
|
|
}
|
|
|
|
void stream_close(server *srv, stream *s1, stream *s2) {
|
|
ev_io_stop(srv->loop, &s1->watcher);
|
|
if (s1->fd != -1) {
|
|
shutdown(s1->fd, SHUT_RDWR);
|
|
close(s1->fd);
|
|
s1->fd = -1;
|
|
}
|
|
ev_io_stop(srv->loop, &s2->watcher);
|
|
if (s2->fd != -1) {
|
|
shutdown(s2->fd, SHUT_RDWR);
|
|
close(s2->fd);
|
|
s2->fd = -1;
|
|
}
|
|
}
|
|
|
|
void stream_clean(server *srv, stream *s1, stream *s2) {
|
|
stream_close(srv, s1, s2);
|
|
if (s1->buffer) { g_string_free(s1->buffer, TRUE); s1->buffer = NULL; }
|
|
if (s2->buffer) { g_string_free(s2->buffer, TRUE); s2->buffer = NULL; }
|
|
}
|
|
|
|
void stream_start(server *srv, stream *s) {
|
|
int events = EV_READ;
|
|
if (s->buffer->len > 0) events |= EV_WRITE;
|
|
ev_io_add_events(srv->loop, &s->watcher, events);
|
|
}
|
|
|
|
gssize stream_closed(server *srv, stream *s) {
|
|
ev_io_stop(srv->loop, &s->watcher);
|
|
if (s->fd != -1) {
|
|
shutdown(s->fd, SHUT_RDWR);
|
|
close(s->fd);
|
|
s->fd = -1;
|
|
}
|
|
s->closed = TRUE;
|
|
g_string_truncate(s->buffer, 0);
|
|
if (s->other->closed) return -1;
|
|
if (s->other->buffer->len == 0) {
|
|
/* nothing to send on the other side, so close that too. */
|
|
return stream_closed(srv, s->other);
|
|
} else {
|
|
/* we can't send the data, so we don't read it */
|
|
/* other stream gets closed if its buffer gets empty */
|
|
ev_io_rem_events(srv->loop, &s->other->watcher, EV_READ);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* -1: connection got closed, 0: nothing to read, n: read n bytes */
|
|
gssize stream_read(server *srv, stream *s, char *buf, gssize bufsize) {
|
|
gssize len;
|
|
while (-1 == (len = read(s->fd, buf, bufsize))) {
|
|
switch (errno) {
|
|
case EAGAIN:
|
|
#if EWOULDBLOCK != EAGAIN
|
|
case EWOULDBLOCK:
|
|
#endif
|
|
/* nothing to read */
|
|
return 0;
|
|
case ECONNRESET:
|
|
return stream_closed(srv, s);
|
|
case EINTR: /* try again */
|
|
break;
|
|
default:
|
|
g_message("read error: %s", g_strerror(errno));
|
|
stream_close(srv, s, s->other);
|
|
return -1;
|
|
}
|
|
}
|
|
if (0 == len) { /* connection closed */
|
|
return stream_closed(srv, s);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
void stream_append(server *srv, stream *s, char *buf, gssize bufsize) {
|
|
if (s->closed) {
|
|
ev_io_rem_events(srv->loop, &s->other->watcher, EV_READ);
|
|
return;
|
|
}
|
|
g_string_append_len(s->buffer, buf, bufsize);
|
|
if (s->buffer->len > 0) ev_io_add_events(srv->loop, &s->watcher, EV_WRITE);
|
|
if (s->buffer->len > MAX_STREAM_BUF_SIZE) ev_io_rem_events(srv->loop, &s->other->watcher, EV_READ);
|
|
}
|
|
|
|
/* -1: connection closed, n: wrote n bytes */
|
|
gssize stream_write(server *srv, stream *s) {
|
|
gssize len;
|
|
while (-1 == (len = write(s->fd, s->buffer->str, s->buffer->len))) {
|
|
switch (errno) {
|
|
case EAGAIN:
|
|
#if EWOULDBLOCK != EAGAIN
|
|
case EWOULDBLOCK:
|
|
#endif
|
|
/* try again later */
|
|
return 0;
|
|
case ECONNRESET:
|
|
case EPIPE:
|
|
return stream_closed(srv, s);
|
|
case EINTR: /* try again */
|
|
break;
|
|
default:
|
|
g_message("write error: %s", g_strerror(errno));
|
|
stream_close(srv, s, s->other);
|
|
return -1;
|
|
}
|
|
}
|
|
g_string_erase(s->buffer, 0, len);
|
|
if (s->buffer->len == 0) {
|
|
if (s->other->closed) return stream_closed(srv, s);
|
|
ev_io_rem_events(srv->loop, &s->watcher, EV_WRITE);
|
|
}
|
|
if (s->buffer->len < MAX_STREAM_BUF_SIZE && !s->other->closed)
|
|
ev_io_add_events(srv->loop, &s->other->watcher, EV_READ);
|
|
return 0;
|
|
}
|