/* ==========================================================================
* libevnet/src/bufio-pipe.c - Network server library for libevent.
* --------------------------------------------------------------------------
* Copyright (c) 2006 William Ahern
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
* ==========================================================================
*/
#include <stddef.h> /* size_t */
#include <assert.h>
#include <sys/queue.h> /* SLIST */
#include <sys/time.h> /* struct timeval */
#include "bufio.h" /* struct bufio_sink struct bufio_source */
#include "pipe.h"
#ifndef NULL
#define NULL 0
#endif
#define BUFIO_PIPE_FRAME_PUSH(p, f) do { \
(f)->pp = &(p); \
SLIST_INSERT_HEAD(&(p)->stack, (f), sle); \
} while(0)
#define BUFIO_PIPE_FRAME_POP(p, f) do { \
if ((p) != 0) { \
assert((f) == SLIST_FIRST(&(p)->stack)); \
SLIST_REMOVE_HEAD(&(p)->stack, sle); \
} \
} while(0)
#define BUFIO_PIPE_FRAME_OKAY(f) ((f)->pp != 0)
const struct bufio_pipe_options bufio_pipe_defaults;
static size_t bufio_pipe_copyfrom(struct bufio_sink *snk, struct bufio_source *src, int flags, enum bufio_errno *ioe) {
struct bufio_pipe *p = BUFIO_CAST_FROM(snk, bufio_pipe, bufio_sink);
if (0 == p->snk.next)
return 0;
return p->snk.next->copyfrom(p->snk.next, src, flags, ioe);
} /* bufio_pipe_copyfrom() */
static size_t bufio_pipe_copyin(struct bufio_sink *snk, void *srcbuf, size_t bufsiz, int flags, enum bufio_errno *ioe) {
struct bufio_pipe *p = BUFIO_CAST_FROM(snk, bufio_pipe, bufio_sink);
if (0 == p->snk.next)
return 0;
return p->snk.next->copyin(p->snk.next, srcbuf, bufsiz, flags, ioe);
} /* bufio_pipe_copyin() */
static size_t bufio_pipe_sink_buffered(struct bufio_sink *snk) {
struct bufio_pipe *p = BUFIO_CAST_FROM(snk, bufio_pipe, bufio_sink);
if (0 == p->snk.next)
return 0;
return p->snk.next->buffered(p->snk.next);
} /* bufio_pipe_sink_buffered() */
static enum bufio_errno bufio_pipe_sink_poll(struct bufio_sink *snk, bufio_sink_poll_cb fn, void *arg, struct timeval *timeout) {
struct bufio_pipe *p = BUFIO_CAST_FROM(snk, bufio_pipe, bufio_sink);
assert(0 == p->snk.fn);
p->snk.fn = fn;
p->snk.arg = arg;
/* Timeout not supported. */
return 0;
} /* bufio_pipe_sink_poll() */
static enum bufio_errno bufio_pipe_sink_cancel(struct bufio_sink *snk, int notify) {
struct bufio_pipe *p = BUFIO_CAST_FROM(snk, bufio_pipe, bufio_sink);
bufio_sink_poll_cb fn;
if (0 != (fn = p->snk.fn)) {
p->snk.fn = 0;
if (notify)
fn(BUFIO_CAST_TO(p, bufio_pipe, bufio_sink), 0, p->snk.arg);
}
return 0;
} /* bufio_pipe_sink_cancel() */
static size_t bufio_pipe_copyto(struct bufio_source *src, struct bufio_sink *snk, int flags, enum bufio_errno *ioe) {
struct bufio_pipe *p = BUFIO_CAST_FROM(src, bufio_pipe, bufio_source);
if (0 == p->src.next)
return 0;
return p->src.next->copyto(p->src.next, snk, flags, ioe);
} /* bufio_pipe_copyto() */
static size_t bufio_pipe_copyout(struct bufio_source *src, void *buf, size_t bufsiz, int flags, enum bufio_errno *ioe) {
struct bufio_pipe *p = BUFIO_CAST_FROM(src, bufio_pipe, bufio_source);
if (0 == p->src.next)
return 0;
return p->src.next->copyout(p->src.next, buf, bufsiz, flags, ioe);
} /* bufio_pipe_copyout() */
static size_t bufio_pipe_source_buffered(struct bufio_source *src) {
struct bufio_pipe *p = BUFIO_CAST_FROM(src, bufio_pipe, bufio_source);
if (0 == p->src.next)
return 0;
return p->src.next->buffered(p->src.next);
} /* bufio_pipe_source_buffered() */
static enum bufio_errno bufio_pipe_source_poll(struct bufio_source *src, bufio_source_poll_cb fn, void *arg, struct timeval *timeout) {
struct bufio_pipe *p = BUFIO_CAST_FROM(src, bufio_pipe, bufio_source);
assert(0 == p->src.fn);
p->src.fn = fn;
p->src.arg = arg;
/* Timeout not supported. */
return 0;
} /* bufio_pipe_source_poll() */
static enum bufio_errno bufio_pipe_source_cancel(struct bufio_source *src, int notify) {
struct bufio_pipe *p = BUFIO_CAST_FROM(src, bufio_pipe, bufio_source);
bufio_source_poll_cb fn;
if (0 != (fn = p->src.fn)) {
p->src.fn = 0;
if (notify)
fn(BUFIO_CAST_TO(p, bufio_pipe, bufio_source), 0, p->src.arg);
}
return 0;
} /* bufio_pipe_source_cancel() */
struct bufio_pipe *bufio_pipe_init(struct bufio_pipe *p, const struct bufio_pipe_options *opts) {
static const struct bufio_pipe bufio_pipe_initializer;
struct bufio_source *src;
struct bufio_sink *snk;
*p = bufio_pipe_initializer;
p->opts = *((opts)? opts : &bufio_pipe_defaults);
src = BUFIO_CAST_TO(p, bufio_pipe, bufio_source);
*src = BUFIO_SOURCE_INITIALIZER;
src->copyto = &bufio_pipe_copyto;
src->copyout = &bufio_pipe_copyout;
src->buffered = &bufio_pipe_source_buffered;
src->poll = &bufio_pipe_source_poll;
src->cancel = &bufio_pipe_source_cancel;
snk = BUFIO_CAST_TO(p, bufio_pipe, bufio_sink);
*snk = BUFIO_SINK_INITIALIZER;
snk->copyfrom = &bufio_pipe_copyfrom;
snk->copyin = &bufio_pipe_copyin;
snk->buffered = &bufio_pipe_sink_buffered;
snk->poll = &bufio_pipe_sink_poll;
snk->cancel = &bufio_pipe_sink_cancel;
SLIST_INIT(&p->stack);
return p;
} /* bufio_pipe_init() */
void bufio_pipe_destroy(struct bufio_pipe *p) {
struct bufio_pipe_frame *f;
p->snk.fn = 0;
p->src.fn = 0;
SLIST_FOREACH(f, &p->stack, sle)
*f->pp = 0, f->pp = 0;
SLIST_INIT(&p->stack);
return /* void */;
} /* bufio_pipe_destroy() */
void bufio_pipe_set_source(struct bufio_pipe *p, struct bufio_source *src) {
p->src.next = src;
return /* void */;
} /* bufio_pipe_set_source() */
void bufio_pipe_set_sink(struct bufio_pipe *p, struct bufio_sink *snk) {
p->snk.next = snk;
return /* void */;
} /* bufio_pipe_set_sink() */
struct bufio_source *bufio_pipe_init_source(struct bufio_pipe *p, const struct bufio_pipe_options *opts) {
bufio_pipe_init(p, opts);
return bufio_pipe_to_source(p);
} /* bufio_pipe_init_source() */
struct bufio_sink *bufio_pipe_init_sink(struct bufio_pipe *p, const struct bufio_pipe_options *opts) {
bufio_pipe_init(p, opts);
return bufio_pipe_to_sink(p);
} /* bufio_pipe_init_sink() */
struct bufio_source *bufio_pipe_to_source(struct bufio_pipe *p) {
return BUFIO_CAST_TO(p, bufio_pipe, bufio_source);
} /* bufio_pipe_to_source() */
struct bufio_sink *bufio_pipe_to_sink(struct bufio_pipe *p) {
return BUFIO_CAST_TO(p, bufio_pipe, bufio_sink);
} /* bufio_pipe_to_sink() */
void bufio_pipe_notify(struct bufio_pipe *p) {
struct bufio_pipe_frame f;
bufio_source_poll_cb src_cb;
bufio_sink_poll_cb snk_cb;
BUFIO_PIPE_FRAME_PUSH(p, &f);
if (0 != (snk_cb = p->snk.fn)) {
p->snk.fn = 0;
snk_cb(BUFIO_CAST_TO(p, bufio_pipe, bufio_sink), 0, p->snk.arg);
if (!BUFIO_PIPE_FRAME_OKAY(&f))
return /* void */;
}
if (0 != (src_cb = p->src.fn)) {
p->src.fn = 0;
src_cb(BUFIO_CAST_TO(p, bufio_pipe, bufio_source), 0, p->src.arg);
if (!BUFIO_PIPE_FRAME_OKAY(&f))
return /* void */;
}
return /* void */;
} /* bufio_pipe_notify() */
syntax highlighted by Code2HTML, v. 0.9.1