/* ========================================================================== * 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 /* size_t */ #include #include /* SLIST */ #include /* 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() */