/* ========================================================================== * libevnet/src/bufio-membuf.c - Network server library for libevent. * -------------------------------------------------------------------------- * Copyright (c) 2006 Barracuda Networks, Inc. * 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 /* ENOBUFS */ #include /* memcpy(3) */ #include /* MIN */ #include /* GetLastError SetLastError */ #include /* INVALID_SOCKET */ #include /* struct arena_prototype */ #include "bufio.h" #include "pagebuf.h" #include "membuf.h" const struct bufio_membuf_options bufio_membuf_oneshot = { #ifndef WIN32 .oneshot = 1, #else 1, #endif }; /* bufio_membuf_oneshot */ const struct bufio_membuf_options bufio_membuf_defaults; static size_t bufio_membuf_copyfrom(struct bufio_sink *snk, struct bufio_source *src, int flags, enum bufio_errno *e) { struct bufio_membuf *m = BUFIO_CAST_FROM(snk, bufio_membuf, bufio_sink); size_t n, nbytes = 0; if (0 == bufio_page_nfree(&m->page)) { *e = (m->opts.oneshot)? BUFIO_EPIPE : BUFIO_EAGAIN; return 0; } *e = 0; do { n = src->copyout(src, m->page.cursor.put, bufio_page_nfree(&m->page), flags, e); m->page.cursor.put += n; nbytes += n; } while (n > 0 && 0 < bufio_page_nfree(&m->page)); return nbytes; } /* bufio_membuf_copyfrom() */ static size_t bufio_membuf_copyin(struct bufio_sink *snk, void *srcbuf, size_t bufsiz, int flags, enum bufio_errno *e) { struct bufio_membuf *m = BUFIO_CAST_FROM(snk, bufio_membuf, bufio_sink); size_t nbytes; if (0 == bufio_page_nfree(&m->page)) goto wouldblock; *e = 0; nbytes = MIN(bufio_page_nfree(&m->page), bufsiz); if ((flags & BUFIO_NOFRAG) && nbytes != bufsiz) goto wouldblock; (void)memcpy(m->page.cursor.put, srcbuf, nbytes); m->page.cursor.put += nbytes; return nbytes; wouldblock: *e = (m->opts.oneshot)? BUFIO_EPIPE : BUFIO_EAGAIN; return 0; } /* bufio_membuf_copyin() */ static size_t bufio_membuf_sink_buffered(struct bufio_sink *snk) { return bufio_page_len(&BUFIO_CAST_FROM(snk, bufio_membuf, bufio_sink)->page); } /* bufio_membuf_sink_buffered() */ static size_t bufio_membuf_copyto(struct bufio_source *src, struct bufio_sink *snk, int flags, enum bufio_errno *e) { struct bufio_membuf *m = BUFIO_CAST_FROM(src, bufio_membuf, bufio_source); size_t n, nbytes = 0; *e = 0; if (0 == bufio_page_len(&m->page)) { *e = (m->opts.oneshot)? BUFIO_EEOF : BUFIO_EAGAIN; return 0; } do { n = snk->copyin(snk, m->page.cursor.get, bufio_page_len(&m->page), flags, e); m->page.cursor.get += n; nbytes += n; } while (n > 0 && 0 < bufio_page_len(&m->page)); return nbytes; } /* bufio_membuf_copyto() */ static size_t bufio_membuf_copyout(struct bufio_source *src, void *buf, size_t bufsiz, int flags, enum bufio_errno *e) { struct bufio_membuf *m = BUFIO_CAST_FROM(src, bufio_membuf, bufio_source); size_t nbytes; *e = 0; if (0 == bufio_page_len(&m->page)) goto wouldblock; nbytes = MIN(bufio_page_len(&m->page), bufsiz); if ((flags && BUFIO_NOFRAG) && nbytes != bufio_page_len(&m->page)) goto wouldblock; (void)memcpy(buf, m->page.cursor.get, nbytes); if (!(flags & BUFIO_PEEK)) m->page.cursor.get += nbytes; return nbytes; wouldblock: *e = (m->opts.oneshot)? BUFIO_EEOF : BUFIO_EAGAIN; return 0; } /* bufio_membuf_copyout() */ static size_t bufio_membuf_source_buffered(struct bufio_source *src) { return bufio_page_len(&BUFIO_CAST_FROM(src, bufio_membuf, bufio_source)->page); } /* bufio_membuf_source_buffered() */ struct bufio_membuf *bufio_membuf_init(struct bufio_membuf *m, const struct bufio_membuf_options *opts) { static const struct bufio_membuf bufio_membuf_initializer; struct bufio_source *src; struct bufio_sink *snk; *m = bufio_membuf_initializer; m->opts = *((opts)? opts : &bufio_membuf_defaults); src = BUFIO_CAST_TO(m, bufio_membuf, bufio_source); *src = BUFIO_SOURCE_INITIALIZER; src->copyto = &bufio_membuf_copyto; src->copyout = &bufio_membuf_copyout; src->buffered = &bufio_membuf_source_buffered; snk = BUFIO_CAST_TO(m, bufio_membuf, bufio_sink); *snk = BUFIO_SINK_INITIALIZER; snk->copyfrom = &bufio_membuf_copyfrom; snk->copyin = &bufio_membuf_copyin; snk->buffered = &bufio_membuf_sink_buffered; return m; } /* bufio_membuf_options() */ struct bufio_source *bufio_membuf_init_source(struct bufio_membuf *m, const struct bufio_membuf_options *opts, const void *buf, size_t bufsiz) { bufio_membuf_init(m, opts); m->page.base = m->page.cursor.get = (unsigned char *)buf; m->page.cursor.end = m->page.cursor.put = m->page.cursor.get + bufsiz; return bufio_membuf_to_source(m); } /* bufio_membuf_init_source() */ struct bufio_sink *bufio_membuf_init_sink(struct bufio_membuf *m, const struct bufio_membuf_options *opts, void *buf, size_t bufsiz) { bufio_membuf_init(m, opts); m->page.base = m->page.cursor.get = m->page.cursor.put = (unsigned char *)buf; m->page.cursor.end = m->page.cursor.get + bufsiz; return bufio_membuf_to_sink(m); } /* bufio_membuf_init_sink() */ struct bufio_source *bufio_membuf_to_source(struct bufio_membuf *m) { return BUFIO_CAST_TO(m, bufio_membuf, bufio_source); } /* bufio_membuf_to_source() */ struct bufio_sink *bufio_membuf_to_sink(struct bufio_membuf *m) { return BUFIO_CAST_TO(m, bufio_membuf, bufio_sink); } /* bufio_membuf_to_sink() */