2
0
Fork 0
lighttpd2/src/main/stream_simple_socket.c

148 lines
3.9 KiB
C

#include <lighttpd/base.h>
void li_stream_simple_socket_close(liIOStream *stream, gboolean aborted) {
int fd = li_event_io_fd(&stream->io_watcher);
li_event_detach(&stream->io_watcher);
if (-1 == fd) return;
stream->out_closed = stream->in_closed = TRUE;
stream->can_read = stream->can_write = FALSE;
if (NULL != stream->stream_in.out) {
stream->stream_in.out->is_closed = TRUE;
}
if (aborted || stream->in_closed) {
li_iostream_acquire(stream);
fd = li_iostream_reset(stream);
if (-1 != fd) {
shutdown(fd, SHUT_RDWR);
close(fd);
}
} else {
liWorker *wrk = li_worker_from_iostream(stream);
li_event_clear(&stream->io_watcher);
shutdown(fd, SHUT_WR);
li_stream_disconnect(&stream->stream_out);
li_worker_add_closing_socket(wrk, fd);
}
}
static void stream_simple_socket_read(liIOStream *stream, gpointer *data) {
liNetworkStatus res;
GError *err = NULL;
liWorker *wrk = li_worker_from_iostream(stream);
int fd = li_event_io_fd(&stream->io_watcher);
liChunkQueue *raw_in = stream->stream_in.out;
if (NULL == *data && NULL != wrk->network_read_buf) {
/* reuse worker buf if needed */
*data = wrk->network_read_buf;
wrk->network_read_buf = NULL;
}
{
liBuffer *raw_in_buffer = *data;
res = li_network_read(fd, raw_in, &raw_in_buffer, &err);
*data = raw_in_buffer;
}
if (NULL == wrk->network_read_buf && NULL != *data
&& 1 == g_atomic_int_get(&((liBuffer*)*data)->refcount)) {
/* move buffer back to worker if we didn't use it */
wrk->network_read_buf = *data;
*data = NULL;
}
switch (res) {
case LI_NETWORK_STATUS_SUCCESS:
break;
case LI_NETWORK_STATUS_FATAL_ERROR:
ERROR(wrk->srv, "network read fatal error: %s", NULL != err ? err->message : "(unknown)");
g_error_free(err);
li_stream_simple_socket_close(stream, TRUE);
break;
case LI_NETWORK_STATUS_CONNECTION_CLOSE:
li_event_io_rem_events(&stream->io_watcher, LI_EV_READ);
stream->stream_in.out->is_closed = TRUE;
stream->in_closed = TRUE;
stream->can_read = FALSE;
break;
case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
stream->can_read = FALSE;
break;
}
}
static void stream_simple_socket_write(liIOStream *stream) {
liNetworkStatus res;
liChunkQueue *raw_out = stream->stream_out.out;
liChunkQueue *from = stream->stream_out.source->out;
int fd = li_event_io_fd(&stream->io_watcher);
liWorker *wrk;
li_chunkqueue_steal_all(raw_out, from);
if (raw_out->length > 0) {
static const goffset WRITE_MAX = 256*1024; /* 256kB */
goffset write_max;
GError *err = NULL;
write_max = WRITE_MAX;
res = li_network_write(fd, raw_out, write_max, &err);
switch (res) {
case LI_NETWORK_STATUS_SUCCESS:
break;
case LI_NETWORK_STATUS_FATAL_ERROR:
wrk = li_worker_from_iostream(stream);
ERROR(wrk->srv, "network write fatal error: %s", NULL != err ? err->message : "(unknown)");
g_error_free(err);
li_stream_simple_socket_close(stream, TRUE);
break;
case LI_NETWORK_STATUS_CONNECTION_CLOSE:
li_stream_simple_socket_close(stream, TRUE);
break;
case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
stream->can_write = FALSE;
break;
}
}
if (0 == raw_out->length && raw_out->is_closed) {
fd = li_event_io_fd(&stream->io_watcher);
li_event_io_rem_events(&stream->io_watcher, LI_EV_WRITE);
if (-1 != fd) shutdown(fd, SHUT_WR);
stream->out_closed = TRUE;
stream->can_write = FALSE;
li_stream_disconnect(&stream->stream_out);
}
}
void li_stream_simple_socket_io_cb(liIOStream *stream, liIOStreamEvent event) {
li_stream_simple_socket_io_cb_with_context(stream, event, &stream->data);
}
void li_stream_simple_socket_io_cb_with_context(liIOStream *stream, liIOStreamEvent event, gpointer *data) {
switch (event) {
case LI_IOSTREAM_READ:
stream_simple_socket_read(stream, data);
break;
case LI_IOSTREAM_WRITE:
stream_simple_socket_write(stream);
break;
case LI_IOSTREAM_DESTROY:
if (NULL != *data) {
li_buffer_release(*data);
*data = NULL;
}
default:
break;
}
}