12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
32b15cb3dSCy Schubert * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
42b15cb3dSCy Schubert *
52b15cb3dSCy Schubert * Redistribution and use in source and binary forms, with or without
62b15cb3dSCy Schubert * modification, are permitted provided that the following conditions
72b15cb3dSCy Schubert * are met:
82b15cb3dSCy Schubert * 1. Redistributions of source code must retain the above copyright
92b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer.
102b15cb3dSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
112b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer in the
122b15cb3dSCy Schubert * documentation and/or other materials provided with the distribution.
132b15cb3dSCy Schubert * 3. The name of the author may not be used to endorse or promote products
142b15cb3dSCy Schubert * derived from this software without specific prior written permission.
152b15cb3dSCy Schubert *
162b15cb3dSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
172b15cb3dSCy Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
182b15cb3dSCy Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
192b15cb3dSCy Schubert * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
202b15cb3dSCy Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
212b15cb3dSCy Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222b15cb3dSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232b15cb3dSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242b15cb3dSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
252b15cb3dSCy Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262b15cb3dSCy Schubert */
272b15cb3dSCy Schubert
282b15cb3dSCy Schubert #include "event2/event-config.h"
292b15cb3dSCy Schubert #include "evconfig-private.h"
302b15cb3dSCy Schubert
312b15cb3dSCy Schubert #ifdef _WIN32
322b15cb3dSCy Schubert #include <winsock2.h>
332b15cb3dSCy Schubert #include <windows.h>
342b15cb3dSCy Schubert #include <io.h>
352b15cb3dSCy Schubert #endif
362b15cb3dSCy Schubert
372b15cb3dSCy Schubert #ifdef EVENT__HAVE_VASPRINTF
382b15cb3dSCy Schubert /* If we have vasprintf, we need to define _GNU_SOURCE before we include
392b15cb3dSCy Schubert * stdio.h. This comes from evconfig-private.h.
402b15cb3dSCy Schubert */
412b15cb3dSCy Schubert #endif
422b15cb3dSCy Schubert
432b15cb3dSCy Schubert #include <sys/types.h>
442b15cb3dSCy Schubert
452b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
462b15cb3dSCy Schubert #include <sys/time.h>
472b15cb3dSCy Schubert #endif
482b15cb3dSCy Schubert
492b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_SOCKET_H
502b15cb3dSCy Schubert #include <sys/socket.h>
512b15cb3dSCy Schubert #endif
522b15cb3dSCy Schubert
532b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_UIO_H
542b15cb3dSCy Schubert #include <sys/uio.h>
552b15cb3dSCy Schubert #endif
562b15cb3dSCy Schubert
572b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_IOCTL_H
582b15cb3dSCy Schubert #include <sys/ioctl.h>
592b15cb3dSCy Schubert #endif
602b15cb3dSCy Schubert
612b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_MMAN_H
622b15cb3dSCy Schubert #include <sys/mman.h>
632b15cb3dSCy Schubert #endif
642b15cb3dSCy Schubert
652b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_SENDFILE_H
662b15cb3dSCy Schubert #include <sys/sendfile.h>
672b15cb3dSCy Schubert #endif
682b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_STAT_H
692b15cb3dSCy Schubert #include <sys/stat.h>
702b15cb3dSCy Schubert #endif
712b15cb3dSCy Schubert
722b15cb3dSCy Schubert
732b15cb3dSCy Schubert #include <errno.h>
742b15cb3dSCy Schubert #include <stdio.h>
752b15cb3dSCy Schubert #include <stdlib.h>
762b15cb3dSCy Schubert #include <string.h>
772b15cb3dSCy Schubert #ifdef EVENT__HAVE_STDARG_H
782b15cb3dSCy Schubert #include <stdarg.h>
792b15cb3dSCy Schubert #endif
802b15cb3dSCy Schubert #ifdef EVENT__HAVE_UNISTD_H
812b15cb3dSCy Schubert #include <unistd.h>
822b15cb3dSCy Schubert #endif
832b15cb3dSCy Schubert #include <limits.h>
842b15cb3dSCy Schubert
852b15cb3dSCy Schubert #include "event2/event.h"
862b15cb3dSCy Schubert #include "event2/buffer.h"
872b15cb3dSCy Schubert #include "event2/buffer_compat.h"
882b15cb3dSCy Schubert #include "event2/bufferevent.h"
892b15cb3dSCy Schubert #include "event2/bufferevent_compat.h"
902b15cb3dSCy Schubert #include "event2/bufferevent_struct.h"
912b15cb3dSCy Schubert #include "event2/thread.h"
922b15cb3dSCy Schubert #include "log-internal.h"
932b15cb3dSCy Schubert #include "mm-internal.h"
942b15cb3dSCy Schubert #include "util-internal.h"
952b15cb3dSCy Schubert #include "evthread-internal.h"
962b15cb3dSCy Schubert #include "evbuffer-internal.h"
972b15cb3dSCy Schubert #include "bufferevent-internal.h"
98*a466cc55SCy Schubert #include "event-internal.h"
992b15cb3dSCy Schubert
1002b15cb3dSCy Schubert /* some systems do not have MAP_FAILED */
1012b15cb3dSCy Schubert #ifndef MAP_FAILED
1022b15cb3dSCy Schubert #define MAP_FAILED ((void *)-1)
1032b15cb3dSCy Schubert #endif
1042b15cb3dSCy Schubert
1052b15cb3dSCy Schubert /* send file support */
1062b15cb3dSCy Schubert #if defined(EVENT__HAVE_SYS_SENDFILE_H) && defined(EVENT__HAVE_SENDFILE) && defined(__linux__)
1072b15cb3dSCy Schubert #define USE_SENDFILE 1
1082b15cb3dSCy Schubert #define SENDFILE_IS_LINUX 1
1092b15cb3dSCy Schubert #elif defined(EVENT__HAVE_SENDFILE) && defined(__FreeBSD__)
1102b15cb3dSCy Schubert #define USE_SENDFILE 1
1112b15cb3dSCy Schubert #define SENDFILE_IS_FREEBSD 1
1122b15cb3dSCy Schubert #elif defined(EVENT__HAVE_SENDFILE) && defined(__APPLE__)
1132b15cb3dSCy Schubert #define USE_SENDFILE 1
1142b15cb3dSCy Schubert #define SENDFILE_IS_MACOSX 1
1152b15cb3dSCy Schubert #elif defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
1162b15cb3dSCy Schubert #define USE_SENDFILE 1
1172b15cb3dSCy Schubert #define SENDFILE_IS_SOLARIS 1
1182b15cb3dSCy Schubert #endif
1192b15cb3dSCy Schubert
1202b15cb3dSCy Schubert /* Mask of user-selectable callback flags. */
1212b15cb3dSCy Schubert #define EVBUFFER_CB_USER_FLAGS 0xffff
1222b15cb3dSCy Schubert /* Mask of all internal-use-only flags. */
1232b15cb3dSCy Schubert #define EVBUFFER_CB_INTERNAL_FLAGS 0xffff0000
1242b15cb3dSCy Schubert
1252b15cb3dSCy Schubert /* Flag set if the callback is using the cb_obsolete function pointer */
1262b15cb3dSCy Schubert #define EVBUFFER_CB_OBSOLETE 0x00040000
1272b15cb3dSCy Schubert
1282b15cb3dSCy Schubert /* evbuffer_chain support */
1292b15cb3dSCy Schubert #define CHAIN_SPACE_PTR(ch) ((ch)->buffer + (ch)->misalign + (ch)->off)
1302b15cb3dSCy Schubert #define CHAIN_SPACE_LEN(ch) ((ch)->flags & EVBUFFER_IMMUTABLE ? \
1312b15cb3dSCy Schubert 0 : (ch)->buffer_len - ((ch)->misalign + (ch)->off))
1322b15cb3dSCy Schubert
1332b15cb3dSCy Schubert #define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
1342b15cb3dSCy Schubert #define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
1352b15cb3dSCy Schubert
1362b15cb3dSCy Schubert /* evbuffer_ptr support */
1372b15cb3dSCy Schubert #define PTR_NOT_FOUND(ptr) do { \
1382b15cb3dSCy Schubert (ptr)->pos = -1; \
1392b15cb3dSCy Schubert (ptr)->internal_.chain = NULL; \
1402b15cb3dSCy Schubert (ptr)->internal_.pos_in_chain = 0; \
1412b15cb3dSCy Schubert } while (0)
1422b15cb3dSCy Schubert
1432b15cb3dSCy Schubert static void evbuffer_chain_align(struct evbuffer_chain *chain);
1442b15cb3dSCy Schubert static int evbuffer_chain_should_realign(struct evbuffer_chain *chain,
1452b15cb3dSCy Schubert size_t datalen);
1462b15cb3dSCy Schubert static void evbuffer_deferred_callback(struct event_callback *cb, void *arg);
1472b15cb3dSCy Schubert static int evbuffer_ptr_memcmp(const struct evbuffer *buf,
1482b15cb3dSCy Schubert const struct evbuffer_ptr *pos, const char *mem, size_t len);
1492b15cb3dSCy Schubert static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
1502b15cb3dSCy Schubert size_t datlen);
1512b15cb3dSCy Schubert static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
1522b15cb3dSCy Schubert size_t howfar);
1532b15cb3dSCy Schubert static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
1542b15cb3dSCy Schubert static inline void evbuffer_chain_incref(struct evbuffer_chain *chain);
1552b15cb3dSCy Schubert
1562b15cb3dSCy Schubert static struct evbuffer_chain *
evbuffer_chain_new(size_t size)1572b15cb3dSCy Schubert evbuffer_chain_new(size_t size)
1582b15cb3dSCy Schubert {
1592b15cb3dSCy Schubert struct evbuffer_chain *chain;
1602b15cb3dSCy Schubert size_t to_alloc;
1612b15cb3dSCy Schubert
162a25439b6SCy Schubert if (size > EVBUFFER_CHAIN_MAX - EVBUFFER_CHAIN_SIZE)
163a25439b6SCy Schubert return (NULL);
164a25439b6SCy Schubert
1652b15cb3dSCy Schubert size += EVBUFFER_CHAIN_SIZE;
1662b15cb3dSCy Schubert
1672b15cb3dSCy Schubert /* get the next largest memory that can hold the buffer */
168a25439b6SCy Schubert if (size < EVBUFFER_CHAIN_MAX / 2) {
1692b15cb3dSCy Schubert to_alloc = MIN_BUFFER_SIZE;
170a25439b6SCy Schubert while (to_alloc < size) {
1712b15cb3dSCy Schubert to_alloc <<= 1;
172a25439b6SCy Schubert }
173a25439b6SCy Schubert } else {
174a25439b6SCy Schubert to_alloc = size;
175a25439b6SCy Schubert }
1762b15cb3dSCy Schubert
1772b15cb3dSCy Schubert /* we get everything in one chunk */
1782b15cb3dSCy Schubert if ((chain = mm_malloc(to_alloc)) == NULL)
1792b15cb3dSCy Schubert return (NULL);
1802b15cb3dSCy Schubert
1812b15cb3dSCy Schubert memset(chain, 0, EVBUFFER_CHAIN_SIZE);
1822b15cb3dSCy Schubert
1832b15cb3dSCy Schubert chain->buffer_len = to_alloc - EVBUFFER_CHAIN_SIZE;
1842b15cb3dSCy Schubert
1852b15cb3dSCy Schubert /* this way we can manipulate the buffer to different addresses,
1862b15cb3dSCy Schubert * which is required for mmap for example.
1872b15cb3dSCy Schubert */
188*a466cc55SCy Schubert chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);
1892b15cb3dSCy Schubert
1902b15cb3dSCy Schubert chain->refcnt = 1;
1912b15cb3dSCy Schubert
1922b15cb3dSCy Schubert return (chain);
1932b15cb3dSCy Schubert }
1942b15cb3dSCy Schubert
1952b15cb3dSCy Schubert static inline void
evbuffer_chain_free(struct evbuffer_chain * chain)1962b15cb3dSCy Schubert evbuffer_chain_free(struct evbuffer_chain *chain)
1972b15cb3dSCy Schubert {
1982b15cb3dSCy Schubert EVUTIL_ASSERT(chain->refcnt > 0);
1992b15cb3dSCy Schubert if (--chain->refcnt > 0) {
2002b15cb3dSCy Schubert /* chain is still referenced by other chains */
2012b15cb3dSCy Schubert return;
2022b15cb3dSCy Schubert }
2032b15cb3dSCy Schubert
2042b15cb3dSCy Schubert if (CHAIN_PINNED(chain)) {
2052b15cb3dSCy Schubert /* will get freed once no longer dangling */
2062b15cb3dSCy Schubert chain->refcnt++;
2072b15cb3dSCy Schubert chain->flags |= EVBUFFER_DANGLING;
2082b15cb3dSCy Schubert return;
2092b15cb3dSCy Schubert }
2102b15cb3dSCy Schubert
2112b15cb3dSCy Schubert /* safe to release chain, it's either a referencing
2122b15cb3dSCy Schubert * chain or all references to it have been freed */
2132b15cb3dSCy Schubert if (chain->flags & EVBUFFER_REFERENCE) {
2142b15cb3dSCy Schubert struct evbuffer_chain_reference *info =
2152b15cb3dSCy Schubert EVBUFFER_CHAIN_EXTRA(
2162b15cb3dSCy Schubert struct evbuffer_chain_reference,
2172b15cb3dSCy Schubert chain);
2182b15cb3dSCy Schubert if (info->cleanupfn)
2192b15cb3dSCy Schubert (*info->cleanupfn)(chain->buffer,
2202b15cb3dSCy Schubert chain->buffer_len,
2212b15cb3dSCy Schubert info->extra);
2222b15cb3dSCy Schubert }
2232b15cb3dSCy Schubert if (chain->flags & EVBUFFER_FILESEGMENT) {
2242b15cb3dSCy Schubert struct evbuffer_chain_file_segment *info =
2252b15cb3dSCy Schubert EVBUFFER_CHAIN_EXTRA(
2262b15cb3dSCy Schubert struct evbuffer_chain_file_segment,
2272b15cb3dSCy Schubert chain);
2282b15cb3dSCy Schubert if (info->segment) {
2292b15cb3dSCy Schubert #ifdef _WIN32
2302b15cb3dSCy Schubert if (info->segment->is_mapping)
2312b15cb3dSCy Schubert UnmapViewOfFile(chain->buffer);
2322b15cb3dSCy Schubert #endif
2332b15cb3dSCy Schubert evbuffer_file_segment_free(info->segment);
2342b15cb3dSCy Schubert }
2352b15cb3dSCy Schubert }
2362b15cb3dSCy Schubert if (chain->flags & EVBUFFER_MULTICAST) {
2372b15cb3dSCy Schubert struct evbuffer_multicast_parent *info =
2382b15cb3dSCy Schubert EVBUFFER_CHAIN_EXTRA(
2392b15cb3dSCy Schubert struct evbuffer_multicast_parent,
2402b15cb3dSCy Schubert chain);
2412b15cb3dSCy Schubert /* referencing chain is being freed, decrease
2422b15cb3dSCy Schubert * refcounts of source chain and associated
2432b15cb3dSCy Schubert * evbuffer (which get freed once both reach
2442b15cb3dSCy Schubert * zero) */
2452b15cb3dSCy Schubert EVUTIL_ASSERT(info->source != NULL);
2462b15cb3dSCy Schubert EVUTIL_ASSERT(info->parent != NULL);
2472b15cb3dSCy Schubert EVBUFFER_LOCK(info->source);
2482b15cb3dSCy Schubert evbuffer_chain_free(info->parent);
2492b15cb3dSCy Schubert evbuffer_decref_and_unlock_(info->source);
2502b15cb3dSCy Schubert }
2512b15cb3dSCy Schubert
2522b15cb3dSCy Schubert mm_free(chain);
2532b15cb3dSCy Schubert }
2542b15cb3dSCy Schubert
2552b15cb3dSCy Schubert static void
evbuffer_free_all_chains(struct evbuffer_chain * chain)2562b15cb3dSCy Schubert evbuffer_free_all_chains(struct evbuffer_chain *chain)
2572b15cb3dSCy Schubert {
2582b15cb3dSCy Schubert struct evbuffer_chain *next;
2592b15cb3dSCy Schubert for (; chain; chain = next) {
2602b15cb3dSCy Schubert next = chain->next;
2612b15cb3dSCy Schubert evbuffer_chain_free(chain);
2622b15cb3dSCy Schubert }
2632b15cb3dSCy Schubert }
2642b15cb3dSCy Schubert
2652b15cb3dSCy Schubert #ifndef NDEBUG
2662b15cb3dSCy Schubert static int
evbuffer_chains_all_empty(struct evbuffer_chain * chain)2672b15cb3dSCy Schubert evbuffer_chains_all_empty(struct evbuffer_chain *chain)
2682b15cb3dSCy Schubert {
2692b15cb3dSCy Schubert for (; chain; chain = chain->next) {
2702b15cb3dSCy Schubert if (chain->off)
2712b15cb3dSCy Schubert return 0;
2722b15cb3dSCy Schubert }
2732b15cb3dSCy Schubert return 1;
2742b15cb3dSCy Schubert }
2752b15cb3dSCy Schubert #else
2762b15cb3dSCy Schubert /* The definition is needed for EVUTIL_ASSERT, which uses sizeof to avoid
2772b15cb3dSCy Schubert "unused variable" warnings. */
evbuffer_chains_all_empty(struct evbuffer_chain * chain)2782b15cb3dSCy Schubert static inline int evbuffer_chains_all_empty(struct evbuffer_chain *chain) {
2792b15cb3dSCy Schubert return 1;
2802b15cb3dSCy Schubert }
2812b15cb3dSCy Schubert #endif
2822b15cb3dSCy Schubert
2832b15cb3dSCy Schubert /* Free all trailing chains in 'buf' that are neither pinned nor empty, prior
2842b15cb3dSCy Schubert * to replacing them all with a new chain. Return a pointer to the place
2852b15cb3dSCy Schubert * where the new chain will go.
2862b15cb3dSCy Schubert *
2872b15cb3dSCy Schubert * Internal; requires lock. The caller must fix up buf->last and buf->first
2882b15cb3dSCy Schubert * as needed; they might have been freed.
2892b15cb3dSCy Schubert */
2902b15cb3dSCy Schubert static struct evbuffer_chain **
evbuffer_free_trailing_empty_chains(struct evbuffer * buf)2912b15cb3dSCy Schubert evbuffer_free_trailing_empty_chains(struct evbuffer *buf)
2922b15cb3dSCy Schubert {
2932b15cb3dSCy Schubert struct evbuffer_chain **ch = buf->last_with_datap;
2942b15cb3dSCy Schubert /* Find the first victim chain. It might be *last_with_datap */
2952b15cb3dSCy Schubert while ((*ch) && ((*ch)->off != 0 || CHAIN_PINNED(*ch)))
2962b15cb3dSCy Schubert ch = &(*ch)->next;
2972b15cb3dSCy Schubert if (*ch) {
2982b15cb3dSCy Schubert EVUTIL_ASSERT(evbuffer_chains_all_empty(*ch));
2992b15cb3dSCy Schubert evbuffer_free_all_chains(*ch);
3002b15cb3dSCy Schubert *ch = NULL;
3012b15cb3dSCy Schubert }
3022b15cb3dSCy Schubert return ch;
3032b15cb3dSCy Schubert }
3042b15cb3dSCy Schubert
3052b15cb3dSCy Schubert /* Add a single chain 'chain' to the end of 'buf', freeing trailing empty
3062b15cb3dSCy Schubert * chains as necessary. Requires lock. Does not schedule callbacks.
3072b15cb3dSCy Schubert */
3082b15cb3dSCy Schubert static void
evbuffer_chain_insert(struct evbuffer * buf,struct evbuffer_chain * chain)3092b15cb3dSCy Schubert evbuffer_chain_insert(struct evbuffer *buf,
3102b15cb3dSCy Schubert struct evbuffer_chain *chain)
3112b15cb3dSCy Schubert {
3122b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buf);
3132b15cb3dSCy Schubert if (*buf->last_with_datap == NULL) {
3142b15cb3dSCy Schubert /* There are no chains data on the buffer at all. */
3152b15cb3dSCy Schubert EVUTIL_ASSERT(buf->last_with_datap == &buf->first);
3162b15cb3dSCy Schubert EVUTIL_ASSERT(buf->first == NULL);
3172b15cb3dSCy Schubert buf->first = buf->last = chain;
3182b15cb3dSCy Schubert } else {
3192b15cb3dSCy Schubert struct evbuffer_chain **chp;
3202b15cb3dSCy Schubert chp = evbuffer_free_trailing_empty_chains(buf);
3212b15cb3dSCy Schubert *chp = chain;
3222b15cb3dSCy Schubert if (chain->off)
3232b15cb3dSCy Schubert buf->last_with_datap = chp;
3242b15cb3dSCy Schubert buf->last = chain;
3252b15cb3dSCy Schubert }
3262b15cb3dSCy Schubert buf->total_len += chain->off;
3272b15cb3dSCy Schubert }
3282b15cb3dSCy Schubert
3292b15cb3dSCy Schubert static inline struct evbuffer_chain *
evbuffer_chain_insert_new(struct evbuffer * buf,size_t datlen)3302b15cb3dSCy Schubert evbuffer_chain_insert_new(struct evbuffer *buf, size_t datlen)
3312b15cb3dSCy Schubert {
3322b15cb3dSCy Schubert struct evbuffer_chain *chain;
3332b15cb3dSCy Schubert if ((chain = evbuffer_chain_new(datlen)) == NULL)
3342b15cb3dSCy Schubert return NULL;
3352b15cb3dSCy Schubert evbuffer_chain_insert(buf, chain);
3362b15cb3dSCy Schubert return chain;
3372b15cb3dSCy Schubert }
3382b15cb3dSCy Schubert
3392b15cb3dSCy Schubert void
evbuffer_chain_pin_(struct evbuffer_chain * chain,unsigned flag)3402b15cb3dSCy Schubert evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag)
3412b15cb3dSCy Schubert {
3422b15cb3dSCy Schubert EVUTIL_ASSERT((chain->flags & flag) == 0);
3432b15cb3dSCy Schubert chain->flags |= flag;
3442b15cb3dSCy Schubert }
3452b15cb3dSCy Schubert
3462b15cb3dSCy Schubert void
evbuffer_chain_unpin_(struct evbuffer_chain * chain,unsigned flag)3472b15cb3dSCy Schubert evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag)
3482b15cb3dSCy Schubert {
3492b15cb3dSCy Schubert EVUTIL_ASSERT((chain->flags & flag) != 0);
3502b15cb3dSCy Schubert chain->flags &= ~flag;
3512b15cb3dSCy Schubert if (chain->flags & EVBUFFER_DANGLING)
3522b15cb3dSCy Schubert evbuffer_chain_free(chain);
3532b15cb3dSCy Schubert }
3542b15cb3dSCy Schubert
3552b15cb3dSCy Schubert static inline void
evbuffer_chain_incref(struct evbuffer_chain * chain)3562b15cb3dSCy Schubert evbuffer_chain_incref(struct evbuffer_chain *chain)
3572b15cb3dSCy Schubert {
3582b15cb3dSCy Schubert ++chain->refcnt;
3592b15cb3dSCy Schubert }
3602b15cb3dSCy Schubert
3612b15cb3dSCy Schubert struct evbuffer *
evbuffer_new(void)3622b15cb3dSCy Schubert evbuffer_new(void)
3632b15cb3dSCy Schubert {
3642b15cb3dSCy Schubert struct evbuffer *buffer;
3652b15cb3dSCy Schubert
3662b15cb3dSCy Schubert buffer = mm_calloc(1, sizeof(struct evbuffer));
3672b15cb3dSCy Schubert if (buffer == NULL)
3682b15cb3dSCy Schubert return (NULL);
3692b15cb3dSCy Schubert
3702b15cb3dSCy Schubert LIST_INIT(&buffer->callbacks);
3712b15cb3dSCy Schubert buffer->refcnt = 1;
3722b15cb3dSCy Schubert buffer->last_with_datap = &buffer->first;
3732b15cb3dSCy Schubert
3742b15cb3dSCy Schubert return (buffer);
3752b15cb3dSCy Schubert }
3762b15cb3dSCy Schubert
3772b15cb3dSCy Schubert int
evbuffer_set_flags(struct evbuffer * buf,ev_uint64_t flags)3782b15cb3dSCy Schubert evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags)
3792b15cb3dSCy Schubert {
3802b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
3812b15cb3dSCy Schubert buf->flags |= (ev_uint32_t)flags;
3822b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
3832b15cb3dSCy Schubert return 0;
3842b15cb3dSCy Schubert }
3852b15cb3dSCy Schubert
3862b15cb3dSCy Schubert int
evbuffer_clear_flags(struct evbuffer * buf,ev_uint64_t flags)3872b15cb3dSCy Schubert evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags)
3882b15cb3dSCy Schubert {
3892b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
3902b15cb3dSCy Schubert buf->flags &= ~(ev_uint32_t)flags;
3912b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
3922b15cb3dSCy Schubert return 0;
3932b15cb3dSCy Schubert }
3942b15cb3dSCy Schubert
3952b15cb3dSCy Schubert void
evbuffer_incref_(struct evbuffer * buf)3962b15cb3dSCy Schubert evbuffer_incref_(struct evbuffer *buf)
3972b15cb3dSCy Schubert {
3982b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
3992b15cb3dSCy Schubert ++buf->refcnt;
4002b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
4012b15cb3dSCy Schubert }
4022b15cb3dSCy Schubert
4032b15cb3dSCy Schubert void
evbuffer_incref_and_lock_(struct evbuffer * buf)4042b15cb3dSCy Schubert evbuffer_incref_and_lock_(struct evbuffer *buf)
4052b15cb3dSCy Schubert {
4062b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
4072b15cb3dSCy Schubert ++buf->refcnt;
4082b15cb3dSCy Schubert }
4092b15cb3dSCy Schubert
4102b15cb3dSCy Schubert int
evbuffer_defer_callbacks(struct evbuffer * buffer,struct event_base * base)4112b15cb3dSCy Schubert evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base)
4122b15cb3dSCy Schubert {
4132b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
4142b15cb3dSCy Schubert buffer->cb_queue = base;
4152b15cb3dSCy Schubert buffer->deferred_cbs = 1;
4162b15cb3dSCy Schubert event_deferred_cb_init_(&buffer->deferred,
4172b15cb3dSCy Schubert event_base_get_npriorities(base) / 2,
4182b15cb3dSCy Schubert evbuffer_deferred_callback, buffer);
4192b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
4202b15cb3dSCy Schubert return 0;
4212b15cb3dSCy Schubert }
4222b15cb3dSCy Schubert
4232b15cb3dSCy Schubert int
evbuffer_enable_locking(struct evbuffer * buf,void * lock)4242b15cb3dSCy Schubert evbuffer_enable_locking(struct evbuffer *buf, void *lock)
4252b15cb3dSCy Schubert {
4262b15cb3dSCy Schubert #ifdef EVENT__DISABLE_THREAD_SUPPORT
4272b15cb3dSCy Schubert return -1;
4282b15cb3dSCy Schubert #else
4292b15cb3dSCy Schubert if (buf->lock)
4302b15cb3dSCy Schubert return -1;
4312b15cb3dSCy Schubert
4322b15cb3dSCy Schubert if (!lock) {
4332b15cb3dSCy Schubert EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
4342b15cb3dSCy Schubert if (!lock)
4352b15cb3dSCy Schubert return -1;
4362b15cb3dSCy Schubert buf->lock = lock;
4372b15cb3dSCy Schubert buf->own_lock = 1;
4382b15cb3dSCy Schubert } else {
4392b15cb3dSCy Schubert buf->lock = lock;
4402b15cb3dSCy Schubert buf->own_lock = 0;
4412b15cb3dSCy Schubert }
4422b15cb3dSCy Schubert
4432b15cb3dSCy Schubert return 0;
4442b15cb3dSCy Schubert #endif
4452b15cb3dSCy Schubert }
4462b15cb3dSCy Schubert
4472b15cb3dSCy Schubert void
evbuffer_set_parent_(struct evbuffer * buf,struct bufferevent * bev)4482b15cb3dSCy Schubert evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev)
4492b15cb3dSCy Schubert {
4502b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
4512b15cb3dSCy Schubert buf->parent = bev;
4522b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
4532b15cb3dSCy Schubert }
4542b15cb3dSCy Schubert
4552b15cb3dSCy Schubert static void
evbuffer_run_callbacks(struct evbuffer * buffer,int running_deferred)4562b15cb3dSCy Schubert evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
4572b15cb3dSCy Schubert {
4582b15cb3dSCy Schubert struct evbuffer_cb_entry *cbent, *next;
4592b15cb3dSCy Schubert struct evbuffer_cb_info info;
4602b15cb3dSCy Schubert size_t new_size;
4612b15cb3dSCy Schubert ev_uint32_t mask, masked_val;
4622b15cb3dSCy Schubert int clear = 1;
4632b15cb3dSCy Schubert
4642b15cb3dSCy Schubert if (running_deferred) {
4652b15cb3dSCy Schubert mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
4662b15cb3dSCy Schubert masked_val = EVBUFFER_CB_ENABLED;
4672b15cb3dSCy Schubert } else if (buffer->deferred_cbs) {
4682b15cb3dSCy Schubert mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
4692b15cb3dSCy Schubert masked_val = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
4702b15cb3dSCy Schubert /* Don't zero-out n_add/n_del, since the deferred callbacks
4712b15cb3dSCy Schubert will want to see them. */
4722b15cb3dSCy Schubert clear = 0;
4732b15cb3dSCy Schubert } else {
4742b15cb3dSCy Schubert mask = EVBUFFER_CB_ENABLED;
4752b15cb3dSCy Schubert masked_val = EVBUFFER_CB_ENABLED;
4762b15cb3dSCy Schubert }
4772b15cb3dSCy Schubert
4782b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buffer);
4792b15cb3dSCy Schubert
4802b15cb3dSCy Schubert if (LIST_EMPTY(&buffer->callbacks)) {
4812b15cb3dSCy Schubert buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
4822b15cb3dSCy Schubert return;
4832b15cb3dSCy Schubert }
4842b15cb3dSCy Schubert if (buffer->n_add_for_cb == 0 && buffer->n_del_for_cb == 0)
4852b15cb3dSCy Schubert return;
4862b15cb3dSCy Schubert
4872b15cb3dSCy Schubert new_size = buffer->total_len;
4882b15cb3dSCy Schubert info.orig_size = new_size + buffer->n_del_for_cb - buffer->n_add_for_cb;
4892b15cb3dSCy Schubert info.n_added = buffer->n_add_for_cb;
4902b15cb3dSCy Schubert info.n_deleted = buffer->n_del_for_cb;
4912b15cb3dSCy Schubert if (clear) {
4922b15cb3dSCy Schubert buffer->n_add_for_cb = 0;
4932b15cb3dSCy Schubert buffer->n_del_for_cb = 0;
4942b15cb3dSCy Schubert }
4952b15cb3dSCy Schubert for (cbent = LIST_FIRST(&buffer->callbacks);
4962b15cb3dSCy Schubert cbent != LIST_END(&buffer->callbacks);
4972b15cb3dSCy Schubert cbent = next) {
4982b15cb3dSCy Schubert /* Get the 'next' pointer now in case this callback decides
4992b15cb3dSCy Schubert * to remove itself or something. */
5002b15cb3dSCy Schubert next = LIST_NEXT(cbent, next);
5012b15cb3dSCy Schubert
5022b15cb3dSCy Schubert if ((cbent->flags & mask) != masked_val)
5032b15cb3dSCy Schubert continue;
5042b15cb3dSCy Schubert
5052b15cb3dSCy Schubert if ((cbent->flags & EVBUFFER_CB_OBSOLETE))
5062b15cb3dSCy Schubert cbent->cb.cb_obsolete(buffer,
5072b15cb3dSCy Schubert info.orig_size, new_size, cbent->cbarg);
5082b15cb3dSCy Schubert else
5092b15cb3dSCy Schubert cbent->cb.cb_func(buffer, &info, cbent->cbarg);
5102b15cb3dSCy Schubert }
5112b15cb3dSCy Schubert }
5122b15cb3dSCy Schubert
5132b15cb3dSCy Schubert void
evbuffer_invoke_callbacks_(struct evbuffer * buffer)5142b15cb3dSCy Schubert evbuffer_invoke_callbacks_(struct evbuffer *buffer)
5152b15cb3dSCy Schubert {
5162b15cb3dSCy Schubert if (LIST_EMPTY(&buffer->callbacks)) {
5172b15cb3dSCy Schubert buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
5182b15cb3dSCy Schubert return;
5192b15cb3dSCy Schubert }
5202b15cb3dSCy Schubert
5212b15cb3dSCy Schubert if (buffer->deferred_cbs) {
5222b15cb3dSCy Schubert if (event_deferred_cb_schedule_(buffer->cb_queue, &buffer->deferred)) {
5232b15cb3dSCy Schubert evbuffer_incref_and_lock_(buffer);
5242b15cb3dSCy Schubert if (buffer->parent)
5252b15cb3dSCy Schubert bufferevent_incref_(buffer->parent);
5262b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
5272b15cb3dSCy Schubert }
528*a466cc55SCy Schubert }
5292b15cb3dSCy Schubert
5302b15cb3dSCy Schubert evbuffer_run_callbacks(buffer, 0);
5312b15cb3dSCy Schubert }
5322b15cb3dSCy Schubert
5332b15cb3dSCy Schubert static void
evbuffer_deferred_callback(struct event_callback * cb,void * arg)5342b15cb3dSCy Schubert evbuffer_deferred_callback(struct event_callback *cb, void *arg)
5352b15cb3dSCy Schubert {
5362b15cb3dSCy Schubert struct bufferevent *parent = NULL;
5372b15cb3dSCy Schubert struct evbuffer *buffer = arg;
5382b15cb3dSCy Schubert
5392b15cb3dSCy Schubert /* XXXX It would be better to run these callbacks without holding the
5402b15cb3dSCy Schubert * lock */
5412b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
5422b15cb3dSCy Schubert parent = buffer->parent;
5432b15cb3dSCy Schubert evbuffer_run_callbacks(buffer, 1);
5442b15cb3dSCy Schubert evbuffer_decref_and_unlock_(buffer);
5452b15cb3dSCy Schubert if (parent)
5462b15cb3dSCy Schubert bufferevent_decref_(parent);
5472b15cb3dSCy Schubert }
5482b15cb3dSCy Schubert
5492b15cb3dSCy Schubert static void
evbuffer_remove_all_callbacks(struct evbuffer * buffer)5502b15cb3dSCy Schubert evbuffer_remove_all_callbacks(struct evbuffer *buffer)
5512b15cb3dSCy Schubert {
5522b15cb3dSCy Schubert struct evbuffer_cb_entry *cbent;
5532b15cb3dSCy Schubert
5542b15cb3dSCy Schubert while ((cbent = LIST_FIRST(&buffer->callbacks))) {
5552b15cb3dSCy Schubert LIST_REMOVE(cbent, next);
5562b15cb3dSCy Schubert mm_free(cbent);
5572b15cb3dSCy Schubert }
5582b15cb3dSCy Schubert }
5592b15cb3dSCy Schubert
5602b15cb3dSCy Schubert void
evbuffer_decref_and_unlock_(struct evbuffer * buffer)5612b15cb3dSCy Schubert evbuffer_decref_and_unlock_(struct evbuffer *buffer)
5622b15cb3dSCy Schubert {
5632b15cb3dSCy Schubert struct evbuffer_chain *chain, *next;
5642b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buffer);
5652b15cb3dSCy Schubert
5662b15cb3dSCy Schubert EVUTIL_ASSERT(buffer->refcnt > 0);
5672b15cb3dSCy Schubert
5682b15cb3dSCy Schubert if (--buffer->refcnt > 0) {
5692b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
5702b15cb3dSCy Schubert return;
5712b15cb3dSCy Schubert }
5722b15cb3dSCy Schubert
5732b15cb3dSCy Schubert for (chain = buffer->first; chain != NULL; chain = next) {
5742b15cb3dSCy Schubert next = chain->next;
5752b15cb3dSCy Schubert evbuffer_chain_free(chain);
5762b15cb3dSCy Schubert }
5772b15cb3dSCy Schubert evbuffer_remove_all_callbacks(buffer);
5782b15cb3dSCy Schubert if (buffer->deferred_cbs)
5792b15cb3dSCy Schubert event_deferred_cb_cancel_(buffer->cb_queue, &buffer->deferred);
5802b15cb3dSCy Schubert
5812b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
5822b15cb3dSCy Schubert if (buffer->own_lock)
5832b15cb3dSCy Schubert EVTHREAD_FREE_LOCK(buffer->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
5842b15cb3dSCy Schubert mm_free(buffer);
5852b15cb3dSCy Schubert }
5862b15cb3dSCy Schubert
5872b15cb3dSCy Schubert void
evbuffer_free(struct evbuffer * buffer)5882b15cb3dSCy Schubert evbuffer_free(struct evbuffer *buffer)
5892b15cb3dSCy Schubert {
5902b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
5912b15cb3dSCy Schubert evbuffer_decref_and_unlock_(buffer);
5922b15cb3dSCy Schubert }
5932b15cb3dSCy Schubert
5942b15cb3dSCy Schubert void
evbuffer_lock(struct evbuffer * buf)5952b15cb3dSCy Schubert evbuffer_lock(struct evbuffer *buf)
5962b15cb3dSCy Schubert {
5972b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
5982b15cb3dSCy Schubert }
5992b15cb3dSCy Schubert
6002b15cb3dSCy Schubert void
evbuffer_unlock(struct evbuffer * buf)6012b15cb3dSCy Schubert evbuffer_unlock(struct evbuffer *buf)
6022b15cb3dSCy Schubert {
6032b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
6042b15cb3dSCy Schubert }
6052b15cb3dSCy Schubert
6062b15cb3dSCy Schubert size_t
evbuffer_get_length(const struct evbuffer * buffer)6072b15cb3dSCy Schubert evbuffer_get_length(const struct evbuffer *buffer)
6082b15cb3dSCy Schubert {
6092b15cb3dSCy Schubert size_t result;
6102b15cb3dSCy Schubert
6112b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
6122b15cb3dSCy Schubert
6132b15cb3dSCy Schubert result = (buffer->total_len);
6142b15cb3dSCy Schubert
6152b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
6162b15cb3dSCy Schubert
6172b15cb3dSCy Schubert return result;
6182b15cb3dSCy Schubert }
6192b15cb3dSCy Schubert
6202b15cb3dSCy Schubert size_t
evbuffer_get_contiguous_space(const struct evbuffer * buf)6212b15cb3dSCy Schubert evbuffer_get_contiguous_space(const struct evbuffer *buf)
6222b15cb3dSCy Schubert {
6232b15cb3dSCy Schubert struct evbuffer_chain *chain;
6242b15cb3dSCy Schubert size_t result;
6252b15cb3dSCy Schubert
6262b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
6272b15cb3dSCy Schubert chain = buf->first;
6282b15cb3dSCy Schubert result = (chain != NULL ? chain->off : 0);
6292b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
6302b15cb3dSCy Schubert
6312b15cb3dSCy Schubert return result;
6322b15cb3dSCy Schubert }
6332b15cb3dSCy Schubert
6342b15cb3dSCy Schubert size_t
evbuffer_add_iovec(struct evbuffer * buf,struct evbuffer_iovec * vec,int n_vec)6352b15cb3dSCy Schubert evbuffer_add_iovec(struct evbuffer * buf, struct evbuffer_iovec * vec, int n_vec) {
6362b15cb3dSCy Schubert int n;
6372b15cb3dSCy Schubert size_t res;
6382b15cb3dSCy Schubert size_t to_alloc;
6392b15cb3dSCy Schubert
6402b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
6412b15cb3dSCy Schubert
6422b15cb3dSCy Schubert res = to_alloc = 0;
6432b15cb3dSCy Schubert
6442b15cb3dSCy Schubert for (n = 0; n < n_vec; n++) {
6452b15cb3dSCy Schubert to_alloc += vec[n].iov_len;
6462b15cb3dSCy Schubert }
6472b15cb3dSCy Schubert
6482b15cb3dSCy Schubert if (evbuffer_expand_fast_(buf, to_alloc, 2) < 0) {
6492b15cb3dSCy Schubert goto done;
6502b15cb3dSCy Schubert }
6512b15cb3dSCy Schubert
6522b15cb3dSCy Schubert for (n = 0; n < n_vec; n++) {
6532b15cb3dSCy Schubert /* XXX each 'add' call here does a bunch of setup that's
6542b15cb3dSCy Schubert * obviated by evbuffer_expand_fast_, and some cleanup that we
6552b15cb3dSCy Schubert * would like to do only once. Instead we should just extract
6562b15cb3dSCy Schubert * the part of the code that's needed. */
6572b15cb3dSCy Schubert
6582b15cb3dSCy Schubert if (evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len) < 0) {
6592b15cb3dSCy Schubert goto done;
6602b15cb3dSCy Schubert }
6612b15cb3dSCy Schubert
6622b15cb3dSCy Schubert res += vec[n].iov_len;
6632b15cb3dSCy Schubert }
6642b15cb3dSCy Schubert
6652b15cb3dSCy Schubert done:
6662b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
6672b15cb3dSCy Schubert return res;
6682b15cb3dSCy Schubert }
6692b15cb3dSCy Schubert
6702b15cb3dSCy Schubert int
evbuffer_reserve_space(struct evbuffer * buf,ev_ssize_t size,struct evbuffer_iovec * vec,int n_vecs)6712b15cb3dSCy Schubert evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
6722b15cb3dSCy Schubert struct evbuffer_iovec *vec, int n_vecs)
6732b15cb3dSCy Schubert {
6742b15cb3dSCy Schubert struct evbuffer_chain *chain, **chainp;
6752b15cb3dSCy Schubert int n = -1;
6762b15cb3dSCy Schubert
6772b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
6782b15cb3dSCy Schubert if (buf->freeze_end)
6792b15cb3dSCy Schubert goto done;
6802b15cb3dSCy Schubert if (n_vecs < 1)
6812b15cb3dSCy Schubert goto done;
6822b15cb3dSCy Schubert if (n_vecs == 1) {
6832b15cb3dSCy Schubert if ((chain = evbuffer_expand_singlechain(buf, size)) == NULL)
6842b15cb3dSCy Schubert goto done;
6852b15cb3dSCy Schubert
686*a466cc55SCy Schubert vec[0].iov_base = (void *)CHAIN_SPACE_PTR(chain);
6872b15cb3dSCy Schubert vec[0].iov_len = (size_t)CHAIN_SPACE_LEN(chain);
6882b15cb3dSCy Schubert EVUTIL_ASSERT(size<0 || (size_t)vec[0].iov_len >= (size_t)size);
6892b15cb3dSCy Schubert n = 1;
6902b15cb3dSCy Schubert } else {
6912b15cb3dSCy Schubert if (evbuffer_expand_fast_(buf, size, n_vecs)<0)
6922b15cb3dSCy Schubert goto done;
6932b15cb3dSCy Schubert n = evbuffer_read_setup_vecs_(buf, size, vec, n_vecs,
6942b15cb3dSCy Schubert &chainp, 0);
6952b15cb3dSCy Schubert }
6962b15cb3dSCy Schubert
6972b15cb3dSCy Schubert done:
6982b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
6992b15cb3dSCy Schubert return n;
7002b15cb3dSCy Schubert
7012b15cb3dSCy Schubert }
7022b15cb3dSCy Schubert
7032b15cb3dSCy Schubert static int
advance_last_with_data(struct evbuffer * buf)7042b15cb3dSCy Schubert advance_last_with_data(struct evbuffer *buf)
7052b15cb3dSCy Schubert {
7062b15cb3dSCy Schubert int n = 0;
707*a466cc55SCy Schubert struct evbuffer_chain **chainp = buf->last_with_datap;
708*a466cc55SCy Schubert
7092b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buf);
7102b15cb3dSCy Schubert
711*a466cc55SCy Schubert if (!*chainp)
7122b15cb3dSCy Schubert return 0;
7132b15cb3dSCy Schubert
714*a466cc55SCy Schubert while ((*chainp)->next) {
715*a466cc55SCy Schubert chainp = &(*chainp)->next;
716*a466cc55SCy Schubert if ((*chainp)->off)
717*a466cc55SCy Schubert buf->last_with_datap = chainp;
7182b15cb3dSCy Schubert ++n;
7192b15cb3dSCy Schubert }
7202b15cb3dSCy Schubert return n;
7212b15cb3dSCy Schubert }
7222b15cb3dSCy Schubert
7232b15cb3dSCy Schubert int
evbuffer_commit_space(struct evbuffer * buf,struct evbuffer_iovec * vec,int n_vecs)7242b15cb3dSCy Schubert evbuffer_commit_space(struct evbuffer *buf,
7252b15cb3dSCy Schubert struct evbuffer_iovec *vec, int n_vecs)
7262b15cb3dSCy Schubert {
7272b15cb3dSCy Schubert struct evbuffer_chain *chain, **firstchainp, **chainp;
7282b15cb3dSCy Schubert int result = -1;
7292b15cb3dSCy Schubert size_t added = 0;
7302b15cb3dSCy Schubert int i;
7312b15cb3dSCy Schubert
7322b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
7332b15cb3dSCy Schubert
7342b15cb3dSCy Schubert if (buf->freeze_end)
7352b15cb3dSCy Schubert goto done;
7362b15cb3dSCy Schubert if (n_vecs == 0) {
7372b15cb3dSCy Schubert result = 0;
7382b15cb3dSCy Schubert goto done;
7392b15cb3dSCy Schubert } else if (n_vecs == 1 &&
7402b15cb3dSCy Schubert (buf->last && vec[0].iov_base == (void *)CHAIN_SPACE_PTR(buf->last))) {
7412b15cb3dSCy Schubert /* The user only got or used one chain; it might not
7422b15cb3dSCy Schubert * be the first one with space in it. */
7432b15cb3dSCy Schubert if ((size_t)vec[0].iov_len > (size_t)CHAIN_SPACE_LEN(buf->last))
7442b15cb3dSCy Schubert goto done;
7452b15cb3dSCy Schubert buf->last->off += vec[0].iov_len;
7462b15cb3dSCy Schubert added = vec[0].iov_len;
7472b15cb3dSCy Schubert if (added)
7482b15cb3dSCy Schubert advance_last_with_data(buf);
7492b15cb3dSCy Schubert goto okay;
7502b15cb3dSCy Schubert }
7512b15cb3dSCy Schubert
7522b15cb3dSCy Schubert /* Advance 'firstchain' to the first chain with space in it. */
7532b15cb3dSCy Schubert firstchainp = buf->last_with_datap;
7542b15cb3dSCy Schubert if (!*firstchainp)
7552b15cb3dSCy Schubert goto done;
7562b15cb3dSCy Schubert if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
7572b15cb3dSCy Schubert firstchainp = &(*firstchainp)->next;
7582b15cb3dSCy Schubert }
7592b15cb3dSCy Schubert
7602b15cb3dSCy Schubert chain = *firstchainp;
7612b15cb3dSCy Schubert /* pass 1: make sure that the pointers and lengths of vecs[] are in
7622b15cb3dSCy Schubert * bounds before we try to commit anything. */
7632b15cb3dSCy Schubert for (i=0; i<n_vecs; ++i) {
7642b15cb3dSCy Schubert if (!chain)
7652b15cb3dSCy Schubert goto done;
7662b15cb3dSCy Schubert if (vec[i].iov_base != (void *)CHAIN_SPACE_PTR(chain) ||
7672b15cb3dSCy Schubert (size_t)vec[i].iov_len > CHAIN_SPACE_LEN(chain))
7682b15cb3dSCy Schubert goto done;
7692b15cb3dSCy Schubert chain = chain->next;
7702b15cb3dSCy Schubert }
7712b15cb3dSCy Schubert /* pass 2: actually adjust all the chains. */
7722b15cb3dSCy Schubert chainp = firstchainp;
7732b15cb3dSCy Schubert for (i=0; i<n_vecs; ++i) {
7742b15cb3dSCy Schubert (*chainp)->off += vec[i].iov_len;
7752b15cb3dSCy Schubert added += vec[i].iov_len;
7762b15cb3dSCy Schubert if (vec[i].iov_len) {
7772b15cb3dSCy Schubert buf->last_with_datap = chainp;
7782b15cb3dSCy Schubert }
7792b15cb3dSCy Schubert chainp = &(*chainp)->next;
7802b15cb3dSCy Schubert }
7812b15cb3dSCy Schubert
7822b15cb3dSCy Schubert okay:
7832b15cb3dSCy Schubert buf->total_len += added;
7842b15cb3dSCy Schubert buf->n_add_for_cb += added;
7852b15cb3dSCy Schubert result = 0;
7862b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
7872b15cb3dSCy Schubert
7882b15cb3dSCy Schubert done:
7892b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
7902b15cb3dSCy Schubert return result;
7912b15cb3dSCy Schubert }
7922b15cb3dSCy Schubert
7932b15cb3dSCy Schubert static inline int
HAS_PINNED_R(struct evbuffer * buf)7942b15cb3dSCy Schubert HAS_PINNED_R(struct evbuffer *buf)
7952b15cb3dSCy Schubert {
7962b15cb3dSCy Schubert return (buf->last && CHAIN_PINNED_R(buf->last));
7972b15cb3dSCy Schubert }
7982b15cb3dSCy Schubert
7992b15cb3dSCy Schubert static inline void
ZERO_CHAIN(struct evbuffer * dst)8002b15cb3dSCy Schubert ZERO_CHAIN(struct evbuffer *dst)
8012b15cb3dSCy Schubert {
8022b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(dst);
8032b15cb3dSCy Schubert dst->first = NULL;
8042b15cb3dSCy Schubert dst->last = NULL;
8052b15cb3dSCy Schubert dst->last_with_datap = &(dst)->first;
8062b15cb3dSCy Schubert dst->total_len = 0;
8072b15cb3dSCy Schubert }
8082b15cb3dSCy Schubert
8092b15cb3dSCy Schubert /* Prepares the contents of src to be moved to another buffer by removing
8102b15cb3dSCy Schubert * read-pinned chains. The first pinned chain is saved in first, and the
8112b15cb3dSCy Schubert * last in last. If src has no read-pinned chains, first and last are set
8122b15cb3dSCy Schubert * to NULL. */
8132b15cb3dSCy Schubert static int
PRESERVE_PINNED(struct evbuffer * src,struct evbuffer_chain ** first,struct evbuffer_chain ** last)8142b15cb3dSCy Schubert PRESERVE_PINNED(struct evbuffer *src, struct evbuffer_chain **first,
8152b15cb3dSCy Schubert struct evbuffer_chain **last)
8162b15cb3dSCy Schubert {
8172b15cb3dSCy Schubert struct evbuffer_chain *chain, **pinned;
8182b15cb3dSCy Schubert
8192b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(src);
8202b15cb3dSCy Schubert
8212b15cb3dSCy Schubert if (!HAS_PINNED_R(src)) {
8222b15cb3dSCy Schubert *first = *last = NULL;
8232b15cb3dSCy Schubert return 0;
8242b15cb3dSCy Schubert }
8252b15cb3dSCy Schubert
8262b15cb3dSCy Schubert pinned = src->last_with_datap;
8272b15cb3dSCy Schubert if (!CHAIN_PINNED_R(*pinned))
8282b15cb3dSCy Schubert pinned = &(*pinned)->next;
8292b15cb3dSCy Schubert EVUTIL_ASSERT(CHAIN_PINNED_R(*pinned));
8302b15cb3dSCy Schubert chain = *first = *pinned;
8312b15cb3dSCy Schubert *last = src->last;
8322b15cb3dSCy Schubert
8332b15cb3dSCy Schubert /* If there's data in the first pinned chain, we need to allocate
8342b15cb3dSCy Schubert * a new chain and copy the data over. */
8352b15cb3dSCy Schubert if (chain->off) {
8362b15cb3dSCy Schubert struct evbuffer_chain *tmp;
8372b15cb3dSCy Schubert
8382b15cb3dSCy Schubert EVUTIL_ASSERT(pinned == src->last_with_datap);
8392b15cb3dSCy Schubert tmp = evbuffer_chain_new(chain->off);
8402b15cb3dSCy Schubert if (!tmp)
8412b15cb3dSCy Schubert return -1;
8422b15cb3dSCy Schubert memcpy(tmp->buffer, chain->buffer + chain->misalign,
8432b15cb3dSCy Schubert chain->off);
8442b15cb3dSCy Schubert tmp->off = chain->off;
8452b15cb3dSCy Schubert *src->last_with_datap = tmp;
8462b15cb3dSCy Schubert src->last = tmp;
8472b15cb3dSCy Schubert chain->misalign += chain->off;
8482b15cb3dSCy Schubert chain->off = 0;
8492b15cb3dSCy Schubert } else {
8502b15cb3dSCy Schubert src->last = *src->last_with_datap;
8512b15cb3dSCy Schubert *pinned = NULL;
8522b15cb3dSCy Schubert }
8532b15cb3dSCy Schubert
8542b15cb3dSCy Schubert return 0;
8552b15cb3dSCy Schubert }
8562b15cb3dSCy Schubert
8572b15cb3dSCy Schubert static inline void
RESTORE_PINNED(struct evbuffer * src,struct evbuffer_chain * pinned,struct evbuffer_chain * last)8582b15cb3dSCy Schubert RESTORE_PINNED(struct evbuffer *src, struct evbuffer_chain *pinned,
8592b15cb3dSCy Schubert struct evbuffer_chain *last)
8602b15cb3dSCy Schubert {
8612b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(src);
8622b15cb3dSCy Schubert
8632b15cb3dSCy Schubert if (!pinned) {
8642b15cb3dSCy Schubert ZERO_CHAIN(src);
8652b15cb3dSCy Schubert return;
8662b15cb3dSCy Schubert }
8672b15cb3dSCy Schubert
8682b15cb3dSCy Schubert src->first = pinned;
8692b15cb3dSCy Schubert src->last = last;
8702b15cb3dSCy Schubert src->last_with_datap = &src->first;
8712b15cb3dSCy Schubert src->total_len = 0;
8722b15cb3dSCy Schubert }
8732b15cb3dSCy Schubert
8742b15cb3dSCy Schubert static inline void
COPY_CHAIN(struct evbuffer * dst,struct evbuffer * src)8752b15cb3dSCy Schubert COPY_CHAIN(struct evbuffer *dst, struct evbuffer *src)
8762b15cb3dSCy Schubert {
8772b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(dst);
8782b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(src);
8792b15cb3dSCy Schubert dst->first = src->first;
8802b15cb3dSCy Schubert if (src->last_with_datap == &src->first)
8812b15cb3dSCy Schubert dst->last_with_datap = &dst->first;
8822b15cb3dSCy Schubert else
8832b15cb3dSCy Schubert dst->last_with_datap = src->last_with_datap;
8842b15cb3dSCy Schubert dst->last = src->last;
8852b15cb3dSCy Schubert dst->total_len = src->total_len;
8862b15cb3dSCy Schubert }
8872b15cb3dSCy Schubert
8882b15cb3dSCy Schubert static void
APPEND_CHAIN(struct evbuffer * dst,struct evbuffer * src)8892b15cb3dSCy Schubert APPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
8902b15cb3dSCy Schubert {
891*a466cc55SCy Schubert struct evbuffer_chain **chp;
892*a466cc55SCy Schubert
8932b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(dst);
8942b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(src);
895*a466cc55SCy Schubert
896*a466cc55SCy Schubert chp = evbuffer_free_trailing_empty_chains(dst);
897*a466cc55SCy Schubert *chp = src->first;
898*a466cc55SCy Schubert
8992b15cb3dSCy Schubert if (src->last_with_datap == &src->first)
900*a466cc55SCy Schubert dst->last_with_datap = chp;
9012b15cb3dSCy Schubert else
9022b15cb3dSCy Schubert dst->last_with_datap = src->last_with_datap;
9032b15cb3dSCy Schubert dst->last = src->last;
9042b15cb3dSCy Schubert dst->total_len += src->total_len;
9052b15cb3dSCy Schubert }
9062b15cb3dSCy Schubert
9072b15cb3dSCy Schubert static inline void
APPEND_CHAIN_MULTICAST(struct evbuffer * dst,struct evbuffer * src)9082b15cb3dSCy Schubert APPEND_CHAIN_MULTICAST(struct evbuffer *dst, struct evbuffer *src)
9092b15cb3dSCy Schubert {
9102b15cb3dSCy Schubert struct evbuffer_chain *tmp;
9112b15cb3dSCy Schubert struct evbuffer_chain *chain = src->first;
9122b15cb3dSCy Schubert struct evbuffer_multicast_parent *extra;
9132b15cb3dSCy Schubert
9142b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(dst);
9152b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(src);
9162b15cb3dSCy Schubert
9172b15cb3dSCy Schubert for (; chain; chain = chain->next) {
9182b15cb3dSCy Schubert if (!chain->off || chain->flags & EVBUFFER_DANGLING) {
9192b15cb3dSCy Schubert /* skip empty chains */
9202b15cb3dSCy Schubert continue;
9212b15cb3dSCy Schubert }
9222b15cb3dSCy Schubert
9232b15cb3dSCy Schubert tmp = evbuffer_chain_new(sizeof(struct evbuffer_multicast_parent));
9242b15cb3dSCy Schubert if (!tmp) {
9252b15cb3dSCy Schubert event_warn("%s: out of memory", __func__);
9262b15cb3dSCy Schubert return;
9272b15cb3dSCy Schubert }
9282b15cb3dSCy Schubert extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
9292b15cb3dSCy Schubert /* reference evbuffer containing source chain so it
9302b15cb3dSCy Schubert * doesn't get released while the chain is still
9312b15cb3dSCy Schubert * being referenced to */
9322b15cb3dSCy Schubert evbuffer_incref_(src);
9332b15cb3dSCy Schubert extra->source = src;
9342b15cb3dSCy Schubert /* reference source chain which now becomes immutable */
9352b15cb3dSCy Schubert evbuffer_chain_incref(chain);
9362b15cb3dSCy Schubert extra->parent = chain;
9372b15cb3dSCy Schubert chain->flags |= EVBUFFER_IMMUTABLE;
9382b15cb3dSCy Schubert tmp->buffer_len = chain->buffer_len;
9392b15cb3dSCy Schubert tmp->misalign = chain->misalign;
9402b15cb3dSCy Schubert tmp->off = chain->off;
9412b15cb3dSCy Schubert tmp->flags |= EVBUFFER_MULTICAST|EVBUFFER_IMMUTABLE;
9422b15cb3dSCy Schubert tmp->buffer = chain->buffer;
9432b15cb3dSCy Schubert evbuffer_chain_insert(dst, tmp);
9442b15cb3dSCy Schubert }
9452b15cb3dSCy Schubert }
9462b15cb3dSCy Schubert
9472b15cb3dSCy Schubert static void
PREPEND_CHAIN(struct evbuffer * dst,struct evbuffer * src)9482b15cb3dSCy Schubert PREPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
9492b15cb3dSCy Schubert {
9502b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(dst);
9512b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(src);
9522b15cb3dSCy Schubert src->last->next = dst->first;
9532b15cb3dSCy Schubert dst->first = src->first;
9542b15cb3dSCy Schubert dst->total_len += src->total_len;
9552b15cb3dSCy Schubert if (*dst->last_with_datap == NULL) {
9562b15cb3dSCy Schubert if (src->last_with_datap == &(src)->first)
9572b15cb3dSCy Schubert dst->last_with_datap = &dst->first;
9582b15cb3dSCy Schubert else
9592b15cb3dSCy Schubert dst->last_with_datap = src->last_with_datap;
9602b15cb3dSCy Schubert } else if (dst->last_with_datap == &dst->first) {
9612b15cb3dSCy Schubert dst->last_with_datap = &src->last->next;
9622b15cb3dSCy Schubert }
9632b15cb3dSCy Schubert }
9642b15cb3dSCy Schubert
9652b15cb3dSCy Schubert int
evbuffer_add_buffer(struct evbuffer * outbuf,struct evbuffer * inbuf)9662b15cb3dSCy Schubert evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
9672b15cb3dSCy Schubert {
9682b15cb3dSCy Schubert struct evbuffer_chain *pinned, *last;
9692b15cb3dSCy Schubert size_t in_total_len, out_total_len;
9702b15cb3dSCy Schubert int result = 0;
9712b15cb3dSCy Schubert
9722b15cb3dSCy Schubert EVBUFFER_LOCK2(inbuf, outbuf);
9732b15cb3dSCy Schubert in_total_len = inbuf->total_len;
9742b15cb3dSCy Schubert out_total_len = outbuf->total_len;
9752b15cb3dSCy Schubert
9762b15cb3dSCy Schubert if (in_total_len == 0 || outbuf == inbuf)
9772b15cb3dSCy Schubert goto done;
9782b15cb3dSCy Schubert
9792b15cb3dSCy Schubert if (outbuf->freeze_end || inbuf->freeze_start) {
9802b15cb3dSCy Schubert result = -1;
9812b15cb3dSCy Schubert goto done;
9822b15cb3dSCy Schubert }
9832b15cb3dSCy Schubert
9842b15cb3dSCy Schubert if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
9852b15cb3dSCy Schubert result = -1;
9862b15cb3dSCy Schubert goto done;
9872b15cb3dSCy Schubert }
9882b15cb3dSCy Schubert
9892b15cb3dSCy Schubert if (out_total_len == 0) {
9902b15cb3dSCy Schubert /* There might be an empty chain at the start of outbuf; free
9912b15cb3dSCy Schubert * it. */
9922b15cb3dSCy Schubert evbuffer_free_all_chains(outbuf->first);
9932b15cb3dSCy Schubert COPY_CHAIN(outbuf, inbuf);
9942b15cb3dSCy Schubert } else {
9952b15cb3dSCy Schubert APPEND_CHAIN(outbuf, inbuf);
9962b15cb3dSCy Schubert }
9972b15cb3dSCy Schubert
9982b15cb3dSCy Schubert RESTORE_PINNED(inbuf, pinned, last);
9992b15cb3dSCy Schubert
10002b15cb3dSCy Schubert inbuf->n_del_for_cb += in_total_len;
10012b15cb3dSCy Schubert outbuf->n_add_for_cb += in_total_len;
10022b15cb3dSCy Schubert
10032b15cb3dSCy Schubert evbuffer_invoke_callbacks_(inbuf);
10042b15cb3dSCy Schubert evbuffer_invoke_callbacks_(outbuf);
10052b15cb3dSCy Schubert
10062b15cb3dSCy Schubert done:
10072b15cb3dSCy Schubert EVBUFFER_UNLOCK2(inbuf, outbuf);
10082b15cb3dSCy Schubert return result;
10092b15cb3dSCy Schubert }
10102b15cb3dSCy Schubert
10112b15cb3dSCy Schubert int
evbuffer_add_buffer_reference(struct evbuffer * outbuf,struct evbuffer * inbuf)10122b15cb3dSCy Schubert evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)
10132b15cb3dSCy Schubert {
10142b15cb3dSCy Schubert size_t in_total_len, out_total_len;
10152b15cb3dSCy Schubert struct evbuffer_chain *chain;
10162b15cb3dSCy Schubert int result = 0;
10172b15cb3dSCy Schubert
10182b15cb3dSCy Schubert EVBUFFER_LOCK2(inbuf, outbuf);
10192b15cb3dSCy Schubert in_total_len = inbuf->total_len;
10202b15cb3dSCy Schubert out_total_len = outbuf->total_len;
10212b15cb3dSCy Schubert chain = inbuf->first;
10222b15cb3dSCy Schubert
10232b15cb3dSCy Schubert if (in_total_len == 0)
10242b15cb3dSCy Schubert goto done;
10252b15cb3dSCy Schubert
10262b15cb3dSCy Schubert if (outbuf->freeze_end || outbuf == inbuf) {
10272b15cb3dSCy Schubert result = -1;
10282b15cb3dSCy Schubert goto done;
10292b15cb3dSCy Schubert }
10302b15cb3dSCy Schubert
10312b15cb3dSCy Schubert for (; chain; chain = chain->next) {
10322b15cb3dSCy Schubert if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE|EVBUFFER_MULTICAST)) != 0) {
10332b15cb3dSCy Schubert /* chain type can not be referenced */
10342b15cb3dSCy Schubert result = -1;
10352b15cb3dSCy Schubert goto done;
10362b15cb3dSCy Schubert }
10372b15cb3dSCy Schubert }
10382b15cb3dSCy Schubert
10392b15cb3dSCy Schubert if (out_total_len == 0) {
10402b15cb3dSCy Schubert /* There might be an empty chain at the start of outbuf; free
10412b15cb3dSCy Schubert * it. */
10422b15cb3dSCy Schubert evbuffer_free_all_chains(outbuf->first);
10432b15cb3dSCy Schubert }
10442b15cb3dSCy Schubert APPEND_CHAIN_MULTICAST(outbuf, inbuf);
10452b15cb3dSCy Schubert
10462b15cb3dSCy Schubert outbuf->n_add_for_cb += in_total_len;
10472b15cb3dSCy Schubert evbuffer_invoke_callbacks_(outbuf);
10482b15cb3dSCy Schubert
10492b15cb3dSCy Schubert done:
10502b15cb3dSCy Schubert EVBUFFER_UNLOCK2(inbuf, outbuf);
10512b15cb3dSCy Schubert return result;
10522b15cb3dSCy Schubert }
10532b15cb3dSCy Schubert
10542b15cb3dSCy Schubert int
evbuffer_prepend_buffer(struct evbuffer * outbuf,struct evbuffer * inbuf)10552b15cb3dSCy Schubert evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
10562b15cb3dSCy Schubert {
10572b15cb3dSCy Schubert struct evbuffer_chain *pinned, *last;
10582b15cb3dSCy Schubert size_t in_total_len, out_total_len;
10592b15cb3dSCy Schubert int result = 0;
10602b15cb3dSCy Schubert
10612b15cb3dSCy Schubert EVBUFFER_LOCK2(inbuf, outbuf);
10622b15cb3dSCy Schubert
10632b15cb3dSCy Schubert in_total_len = inbuf->total_len;
10642b15cb3dSCy Schubert out_total_len = outbuf->total_len;
10652b15cb3dSCy Schubert
10662b15cb3dSCy Schubert if (!in_total_len || inbuf == outbuf)
10672b15cb3dSCy Schubert goto done;
10682b15cb3dSCy Schubert
10692b15cb3dSCy Schubert if (outbuf->freeze_start || inbuf->freeze_start) {
10702b15cb3dSCy Schubert result = -1;
10712b15cb3dSCy Schubert goto done;
10722b15cb3dSCy Schubert }
10732b15cb3dSCy Schubert
10742b15cb3dSCy Schubert if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
10752b15cb3dSCy Schubert result = -1;
10762b15cb3dSCy Schubert goto done;
10772b15cb3dSCy Schubert }
10782b15cb3dSCy Schubert
10792b15cb3dSCy Schubert if (out_total_len == 0) {
10802b15cb3dSCy Schubert /* There might be an empty chain at the start of outbuf; free
10812b15cb3dSCy Schubert * it. */
10822b15cb3dSCy Schubert evbuffer_free_all_chains(outbuf->first);
10832b15cb3dSCy Schubert COPY_CHAIN(outbuf, inbuf);
10842b15cb3dSCy Schubert } else {
10852b15cb3dSCy Schubert PREPEND_CHAIN(outbuf, inbuf);
10862b15cb3dSCy Schubert }
10872b15cb3dSCy Schubert
10882b15cb3dSCy Schubert RESTORE_PINNED(inbuf, pinned, last);
10892b15cb3dSCy Schubert
10902b15cb3dSCy Schubert inbuf->n_del_for_cb += in_total_len;
10912b15cb3dSCy Schubert outbuf->n_add_for_cb += in_total_len;
10922b15cb3dSCy Schubert
10932b15cb3dSCy Schubert evbuffer_invoke_callbacks_(inbuf);
10942b15cb3dSCy Schubert evbuffer_invoke_callbacks_(outbuf);
10952b15cb3dSCy Schubert done:
10962b15cb3dSCy Schubert EVBUFFER_UNLOCK2(inbuf, outbuf);
10972b15cb3dSCy Schubert return result;
10982b15cb3dSCy Schubert }
10992b15cb3dSCy Schubert
11002b15cb3dSCy Schubert int
evbuffer_drain(struct evbuffer * buf,size_t len)11012b15cb3dSCy Schubert evbuffer_drain(struct evbuffer *buf, size_t len)
11022b15cb3dSCy Schubert {
11032b15cb3dSCy Schubert struct evbuffer_chain *chain, *next;
11042b15cb3dSCy Schubert size_t remaining, old_len;
11052b15cb3dSCy Schubert int result = 0;
11062b15cb3dSCy Schubert
11072b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
11082b15cb3dSCy Schubert old_len = buf->total_len;
11092b15cb3dSCy Schubert
11102b15cb3dSCy Schubert if (old_len == 0)
11112b15cb3dSCy Schubert goto done;
11122b15cb3dSCy Schubert
11132b15cb3dSCy Schubert if (buf->freeze_start) {
11142b15cb3dSCy Schubert result = -1;
11152b15cb3dSCy Schubert goto done;
11162b15cb3dSCy Schubert }
11172b15cb3dSCy Schubert
11182b15cb3dSCy Schubert if (len >= old_len && !HAS_PINNED_R(buf)) {
11192b15cb3dSCy Schubert len = old_len;
11202b15cb3dSCy Schubert for (chain = buf->first; chain != NULL; chain = next) {
11212b15cb3dSCy Schubert next = chain->next;
11222b15cb3dSCy Schubert evbuffer_chain_free(chain);
11232b15cb3dSCy Schubert }
11242b15cb3dSCy Schubert
11252b15cb3dSCy Schubert ZERO_CHAIN(buf);
11262b15cb3dSCy Schubert } else {
11272b15cb3dSCy Schubert if (len >= old_len)
11282b15cb3dSCy Schubert len = old_len;
11292b15cb3dSCy Schubert
11302b15cb3dSCy Schubert buf->total_len -= len;
11312b15cb3dSCy Schubert remaining = len;
11322b15cb3dSCy Schubert for (chain = buf->first;
11332b15cb3dSCy Schubert remaining >= chain->off;
11342b15cb3dSCy Schubert chain = next) {
11352b15cb3dSCy Schubert next = chain->next;
11362b15cb3dSCy Schubert remaining -= chain->off;
11372b15cb3dSCy Schubert
11382b15cb3dSCy Schubert if (chain == *buf->last_with_datap) {
11392b15cb3dSCy Schubert buf->last_with_datap = &buf->first;
11402b15cb3dSCy Schubert }
11412b15cb3dSCy Schubert if (&chain->next == buf->last_with_datap)
11422b15cb3dSCy Schubert buf->last_with_datap = &buf->first;
11432b15cb3dSCy Schubert
11442b15cb3dSCy Schubert if (CHAIN_PINNED_R(chain)) {
11452b15cb3dSCy Schubert EVUTIL_ASSERT(remaining == 0);
11462b15cb3dSCy Schubert chain->misalign += chain->off;
11472b15cb3dSCy Schubert chain->off = 0;
11482b15cb3dSCy Schubert break;
11492b15cb3dSCy Schubert } else
11502b15cb3dSCy Schubert evbuffer_chain_free(chain);
11512b15cb3dSCy Schubert }
11522b15cb3dSCy Schubert
11532b15cb3dSCy Schubert buf->first = chain;
1154*a466cc55SCy Schubert EVUTIL_ASSERT(remaining <= chain->off);
11552b15cb3dSCy Schubert chain->misalign += remaining;
11562b15cb3dSCy Schubert chain->off -= remaining;
11572b15cb3dSCy Schubert }
11582b15cb3dSCy Schubert
11592b15cb3dSCy Schubert buf->n_del_for_cb += len;
11602b15cb3dSCy Schubert /* Tell someone about changes in this buffer */
11612b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
11622b15cb3dSCy Schubert
11632b15cb3dSCy Schubert done:
11642b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
11652b15cb3dSCy Schubert return result;
11662b15cb3dSCy Schubert }
11672b15cb3dSCy Schubert
11682b15cb3dSCy Schubert /* Reads data from an event buffer and drains the bytes read */
11692b15cb3dSCy Schubert int
evbuffer_remove(struct evbuffer * buf,void * data_out,size_t datlen)11702b15cb3dSCy Schubert evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
11712b15cb3dSCy Schubert {
11722b15cb3dSCy Schubert ev_ssize_t n;
11732b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
11742b15cb3dSCy Schubert n = evbuffer_copyout_from(buf, NULL, data_out, datlen);
11752b15cb3dSCy Schubert if (n > 0) {
11762b15cb3dSCy Schubert if (evbuffer_drain(buf, n)<0)
11772b15cb3dSCy Schubert n = -1;
11782b15cb3dSCy Schubert }
11792b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
11802b15cb3dSCy Schubert return (int)n;
11812b15cb3dSCy Schubert }
11822b15cb3dSCy Schubert
11832b15cb3dSCy Schubert ev_ssize_t
evbuffer_copyout(struct evbuffer * buf,void * data_out,size_t datlen)11842b15cb3dSCy Schubert evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
11852b15cb3dSCy Schubert {
11862b15cb3dSCy Schubert return evbuffer_copyout_from(buf, NULL, data_out, datlen);
11872b15cb3dSCy Schubert }
11882b15cb3dSCy Schubert
11892b15cb3dSCy Schubert ev_ssize_t
evbuffer_copyout_from(struct evbuffer * buf,const struct evbuffer_ptr * pos,void * data_out,size_t datlen)11902b15cb3dSCy Schubert evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
11912b15cb3dSCy Schubert void *data_out, size_t datlen)
11922b15cb3dSCy Schubert {
11932b15cb3dSCy Schubert /*XXX fails badly on sendfile case. */
11942b15cb3dSCy Schubert struct evbuffer_chain *chain;
11952b15cb3dSCy Schubert char *data = data_out;
11962b15cb3dSCy Schubert size_t nread;
11972b15cb3dSCy Schubert ev_ssize_t result = 0;
11982b15cb3dSCy Schubert size_t pos_in_chain;
11992b15cb3dSCy Schubert
12002b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
12012b15cb3dSCy Schubert
12022b15cb3dSCy Schubert if (pos) {
1203a25439b6SCy Schubert if (datlen > (size_t)(EV_SSIZE_MAX - pos->pos)) {
1204a25439b6SCy Schubert result = -1;
1205a25439b6SCy Schubert goto done;
1206a25439b6SCy Schubert }
12072b15cb3dSCy Schubert chain = pos->internal_.chain;
12082b15cb3dSCy Schubert pos_in_chain = pos->internal_.pos_in_chain;
12092b15cb3dSCy Schubert if (datlen + pos->pos > buf->total_len)
12102b15cb3dSCy Schubert datlen = buf->total_len - pos->pos;
12112b15cb3dSCy Schubert } else {
12122b15cb3dSCy Schubert chain = buf->first;
12132b15cb3dSCy Schubert pos_in_chain = 0;
12142b15cb3dSCy Schubert if (datlen > buf->total_len)
12152b15cb3dSCy Schubert datlen = buf->total_len;
12162b15cb3dSCy Schubert }
12172b15cb3dSCy Schubert
12182b15cb3dSCy Schubert
12192b15cb3dSCy Schubert if (datlen == 0)
12202b15cb3dSCy Schubert goto done;
12212b15cb3dSCy Schubert
12222b15cb3dSCy Schubert if (buf->freeze_start) {
12232b15cb3dSCy Schubert result = -1;
12242b15cb3dSCy Schubert goto done;
12252b15cb3dSCy Schubert }
12262b15cb3dSCy Schubert
12272b15cb3dSCy Schubert nread = datlen;
12282b15cb3dSCy Schubert
12292b15cb3dSCy Schubert while (datlen && datlen >= chain->off - pos_in_chain) {
12302b15cb3dSCy Schubert size_t copylen = chain->off - pos_in_chain;
12312b15cb3dSCy Schubert memcpy(data,
12322b15cb3dSCy Schubert chain->buffer + chain->misalign + pos_in_chain,
12332b15cb3dSCy Schubert copylen);
12342b15cb3dSCy Schubert data += copylen;
12352b15cb3dSCy Schubert datlen -= copylen;
12362b15cb3dSCy Schubert
12372b15cb3dSCy Schubert chain = chain->next;
12382b15cb3dSCy Schubert pos_in_chain = 0;
12392b15cb3dSCy Schubert EVUTIL_ASSERT(chain || datlen==0);
12402b15cb3dSCy Schubert }
12412b15cb3dSCy Schubert
12422b15cb3dSCy Schubert if (datlen) {
12432b15cb3dSCy Schubert EVUTIL_ASSERT(chain);
1244a25439b6SCy Schubert EVUTIL_ASSERT(datlen+pos_in_chain <= chain->off);
1245a25439b6SCy Schubert
12462b15cb3dSCy Schubert memcpy(data, chain->buffer + chain->misalign + pos_in_chain,
12472b15cb3dSCy Schubert datlen);
12482b15cb3dSCy Schubert }
12492b15cb3dSCy Schubert
12502b15cb3dSCy Schubert result = nread;
12512b15cb3dSCy Schubert done:
12522b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
12532b15cb3dSCy Schubert return result;
12542b15cb3dSCy Schubert }
12552b15cb3dSCy Schubert
12562b15cb3dSCy Schubert /* reads data from the src buffer to the dst buffer, avoids memcpy as
12572b15cb3dSCy Schubert * possible. */
12582b15cb3dSCy Schubert /* XXXX should return ev_ssize_t */
12592b15cb3dSCy Schubert int
evbuffer_remove_buffer(struct evbuffer * src,struct evbuffer * dst,size_t datlen)12602b15cb3dSCy Schubert evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
12612b15cb3dSCy Schubert size_t datlen)
12622b15cb3dSCy Schubert {
12632b15cb3dSCy Schubert /*XXX We should have an option to force this to be zero-copy.*/
12642b15cb3dSCy Schubert
12652b15cb3dSCy Schubert /*XXX can fail badly on sendfile case. */
12662b15cb3dSCy Schubert struct evbuffer_chain *chain, *previous;
12672b15cb3dSCy Schubert size_t nread = 0;
12682b15cb3dSCy Schubert int result;
12692b15cb3dSCy Schubert
12702b15cb3dSCy Schubert EVBUFFER_LOCK2(src, dst);
12712b15cb3dSCy Schubert
12722b15cb3dSCy Schubert chain = previous = src->first;
12732b15cb3dSCy Schubert
12742b15cb3dSCy Schubert if (datlen == 0 || dst == src) {
12752b15cb3dSCy Schubert result = 0;
12762b15cb3dSCy Schubert goto done;
12772b15cb3dSCy Schubert }
12782b15cb3dSCy Schubert
12792b15cb3dSCy Schubert if (dst->freeze_end || src->freeze_start) {
12802b15cb3dSCy Schubert result = -1;
12812b15cb3dSCy Schubert goto done;
12822b15cb3dSCy Schubert }
12832b15cb3dSCy Schubert
12842b15cb3dSCy Schubert /* short-cut if there is no more data buffered */
12852b15cb3dSCy Schubert if (datlen >= src->total_len) {
12862b15cb3dSCy Schubert datlen = src->total_len;
12872b15cb3dSCy Schubert evbuffer_add_buffer(dst, src);
12882b15cb3dSCy Schubert result = (int)datlen; /*XXXX should return ev_ssize_t*/
12892b15cb3dSCy Schubert goto done;
12902b15cb3dSCy Schubert }
12912b15cb3dSCy Schubert
12922b15cb3dSCy Schubert /* removes chains if possible */
12932b15cb3dSCy Schubert while (chain->off <= datlen) {
12942b15cb3dSCy Schubert /* We can't remove the last with data from src unless we
12952b15cb3dSCy Schubert * remove all chains, in which case we would have done the if
12962b15cb3dSCy Schubert * block above */
12972b15cb3dSCy Schubert EVUTIL_ASSERT(chain != *src->last_with_datap);
12982b15cb3dSCy Schubert nread += chain->off;
12992b15cb3dSCy Schubert datlen -= chain->off;
13002b15cb3dSCy Schubert previous = chain;
13012b15cb3dSCy Schubert if (src->last_with_datap == &chain->next)
13022b15cb3dSCy Schubert src->last_with_datap = &src->first;
13032b15cb3dSCy Schubert chain = chain->next;
13042b15cb3dSCy Schubert }
13052b15cb3dSCy Schubert
1306*a466cc55SCy Schubert if (chain != src->first) {
13072b15cb3dSCy Schubert /* we can remove the chain */
13082b15cb3dSCy Schubert struct evbuffer_chain **chp;
13092b15cb3dSCy Schubert chp = evbuffer_free_trailing_empty_chains(dst);
13102b15cb3dSCy Schubert
13112b15cb3dSCy Schubert if (dst->first == NULL) {
13122b15cb3dSCy Schubert dst->first = src->first;
13132b15cb3dSCy Schubert } else {
13142b15cb3dSCy Schubert *chp = src->first;
13152b15cb3dSCy Schubert }
13162b15cb3dSCy Schubert dst->last = previous;
13172b15cb3dSCy Schubert previous->next = NULL;
13182b15cb3dSCy Schubert src->first = chain;
13192b15cb3dSCy Schubert advance_last_with_data(dst);
13202b15cb3dSCy Schubert
13212b15cb3dSCy Schubert dst->total_len += nread;
13222b15cb3dSCy Schubert dst->n_add_for_cb += nread;
13232b15cb3dSCy Schubert }
13242b15cb3dSCy Schubert
13252b15cb3dSCy Schubert /* we know that there is more data in the src buffer than
13262b15cb3dSCy Schubert * we want to read, so we manually drain the chain */
13272b15cb3dSCy Schubert evbuffer_add(dst, chain->buffer + chain->misalign, datlen);
13282b15cb3dSCy Schubert chain->misalign += datlen;
13292b15cb3dSCy Schubert chain->off -= datlen;
13302b15cb3dSCy Schubert nread += datlen;
13312b15cb3dSCy Schubert
13322b15cb3dSCy Schubert /* You might think we would want to increment dst->n_add_for_cb
13332b15cb3dSCy Schubert * here too. But evbuffer_add above already took care of that.
13342b15cb3dSCy Schubert */
13352b15cb3dSCy Schubert src->total_len -= nread;
13362b15cb3dSCy Schubert src->n_del_for_cb += nread;
13372b15cb3dSCy Schubert
13382b15cb3dSCy Schubert if (nread) {
13392b15cb3dSCy Schubert evbuffer_invoke_callbacks_(dst);
13402b15cb3dSCy Schubert evbuffer_invoke_callbacks_(src);
13412b15cb3dSCy Schubert }
13422b15cb3dSCy Schubert result = (int)nread;/*XXXX should change return type */
13432b15cb3dSCy Schubert
13442b15cb3dSCy Schubert done:
13452b15cb3dSCy Schubert EVBUFFER_UNLOCK2(src, dst);
13462b15cb3dSCy Schubert return result;
13472b15cb3dSCy Schubert }
13482b15cb3dSCy Schubert
13492b15cb3dSCy Schubert unsigned char *
evbuffer_pullup(struct evbuffer * buf,ev_ssize_t size)13502b15cb3dSCy Schubert evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
13512b15cb3dSCy Schubert {
13522b15cb3dSCy Schubert struct evbuffer_chain *chain, *next, *tmp, *last_with_data;
13532b15cb3dSCy Schubert unsigned char *buffer, *result = NULL;
13542b15cb3dSCy Schubert ev_ssize_t remaining;
13552b15cb3dSCy Schubert int removed_last_with_data = 0;
13562b15cb3dSCy Schubert int removed_last_with_datap = 0;
13572b15cb3dSCy Schubert
13582b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
13592b15cb3dSCy Schubert
13602b15cb3dSCy Schubert chain = buf->first;
13612b15cb3dSCy Schubert
13622b15cb3dSCy Schubert if (size < 0)
13632b15cb3dSCy Schubert size = buf->total_len;
13642b15cb3dSCy Schubert /* if size > buf->total_len, we cannot guarantee to the user that she
13652b15cb3dSCy Schubert * is going to have a long enough buffer afterwards; so we return
13662b15cb3dSCy Schubert * NULL */
13672b15cb3dSCy Schubert if (size == 0 || (size_t)size > buf->total_len)
13682b15cb3dSCy Schubert goto done;
13692b15cb3dSCy Schubert
13702b15cb3dSCy Schubert /* No need to pull up anything; the first size bytes are
13712b15cb3dSCy Schubert * already here. */
13722b15cb3dSCy Schubert if (chain->off >= (size_t)size) {
13732b15cb3dSCy Schubert result = chain->buffer + chain->misalign;
13742b15cb3dSCy Schubert goto done;
13752b15cb3dSCy Schubert }
13762b15cb3dSCy Schubert
13772b15cb3dSCy Schubert /* Make sure that none of the chains we need to copy from is pinned. */
13782b15cb3dSCy Schubert remaining = size - chain->off;
13792b15cb3dSCy Schubert EVUTIL_ASSERT(remaining >= 0);
13802b15cb3dSCy Schubert for (tmp=chain->next; tmp; tmp=tmp->next) {
13812b15cb3dSCy Schubert if (CHAIN_PINNED(tmp))
13822b15cb3dSCy Schubert goto done;
13832b15cb3dSCy Schubert if (tmp->off >= (size_t)remaining)
13842b15cb3dSCy Schubert break;
13852b15cb3dSCy Schubert remaining -= tmp->off;
13862b15cb3dSCy Schubert }
13872b15cb3dSCy Schubert
13882b15cb3dSCy Schubert if (CHAIN_PINNED(chain)) {
13892b15cb3dSCy Schubert size_t old_off = chain->off;
13902b15cb3dSCy Schubert if (CHAIN_SPACE_LEN(chain) < size - chain->off) {
13912b15cb3dSCy Schubert /* not enough room at end of chunk. */
13922b15cb3dSCy Schubert goto done;
13932b15cb3dSCy Schubert }
13942b15cb3dSCy Schubert buffer = CHAIN_SPACE_PTR(chain);
13952b15cb3dSCy Schubert tmp = chain;
13962b15cb3dSCy Schubert tmp->off = size;
13972b15cb3dSCy Schubert size -= old_off;
13982b15cb3dSCy Schubert chain = chain->next;
13992b15cb3dSCy Schubert } else if (chain->buffer_len - chain->misalign >= (size_t)size) {
14002b15cb3dSCy Schubert /* already have enough space in the first chain */
14012b15cb3dSCy Schubert size_t old_off = chain->off;
14022b15cb3dSCy Schubert buffer = chain->buffer + chain->misalign + chain->off;
14032b15cb3dSCy Schubert tmp = chain;
14042b15cb3dSCy Schubert tmp->off = size;
14052b15cb3dSCy Schubert size -= old_off;
14062b15cb3dSCy Schubert chain = chain->next;
14072b15cb3dSCy Schubert } else {
14082b15cb3dSCy Schubert if ((tmp = evbuffer_chain_new(size)) == NULL) {
14092b15cb3dSCy Schubert event_warn("%s: out of memory", __func__);
14102b15cb3dSCy Schubert goto done;
14112b15cb3dSCy Schubert }
14122b15cb3dSCy Schubert buffer = tmp->buffer;
14132b15cb3dSCy Schubert tmp->off = size;
14142b15cb3dSCy Schubert buf->first = tmp;
14152b15cb3dSCy Schubert }
14162b15cb3dSCy Schubert
14172b15cb3dSCy Schubert /* TODO(niels): deal with buffers that point to NULL like sendfile */
14182b15cb3dSCy Schubert
14192b15cb3dSCy Schubert /* Copy and free every chunk that will be entirely pulled into tmp */
14202b15cb3dSCy Schubert last_with_data = *buf->last_with_datap;
14212b15cb3dSCy Schubert for (; chain != NULL && (size_t)size >= chain->off; chain = next) {
14222b15cb3dSCy Schubert next = chain->next;
14232b15cb3dSCy Schubert
1424*a466cc55SCy Schubert if (chain->buffer) {
14252b15cb3dSCy Schubert memcpy(buffer, chain->buffer + chain->misalign, chain->off);
14262b15cb3dSCy Schubert size -= chain->off;
14272b15cb3dSCy Schubert buffer += chain->off;
1428*a466cc55SCy Schubert }
14292b15cb3dSCy Schubert if (chain == last_with_data)
14302b15cb3dSCy Schubert removed_last_with_data = 1;
14312b15cb3dSCy Schubert if (&chain->next == buf->last_with_datap)
14322b15cb3dSCy Schubert removed_last_with_datap = 1;
14332b15cb3dSCy Schubert
14342b15cb3dSCy Schubert evbuffer_chain_free(chain);
14352b15cb3dSCy Schubert }
14362b15cb3dSCy Schubert
14372b15cb3dSCy Schubert if (chain != NULL) {
14382b15cb3dSCy Schubert memcpy(buffer, chain->buffer + chain->misalign, size);
14392b15cb3dSCy Schubert chain->misalign += size;
14402b15cb3dSCy Schubert chain->off -= size;
14412b15cb3dSCy Schubert } else {
14422b15cb3dSCy Schubert buf->last = tmp;
14432b15cb3dSCy Schubert }
14442b15cb3dSCy Schubert
14452b15cb3dSCy Schubert tmp->next = chain;
14462b15cb3dSCy Schubert
14472b15cb3dSCy Schubert if (removed_last_with_data) {
14482b15cb3dSCy Schubert buf->last_with_datap = &buf->first;
14492b15cb3dSCy Schubert } else if (removed_last_with_datap) {
14502b15cb3dSCy Schubert if (buf->first->next && buf->first->next->off)
14512b15cb3dSCy Schubert buf->last_with_datap = &buf->first->next;
14522b15cb3dSCy Schubert else
14532b15cb3dSCy Schubert buf->last_with_datap = &buf->first;
14542b15cb3dSCy Schubert }
14552b15cb3dSCy Schubert
14562b15cb3dSCy Schubert result = (tmp->buffer + tmp->misalign);
14572b15cb3dSCy Schubert
14582b15cb3dSCy Schubert done:
14592b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
14602b15cb3dSCy Schubert return result;
14612b15cb3dSCy Schubert }
14622b15cb3dSCy Schubert
14632b15cb3dSCy Schubert /*
14642b15cb3dSCy Schubert * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
14652b15cb3dSCy Schubert * The returned buffer needs to be freed by the called.
14662b15cb3dSCy Schubert */
14672b15cb3dSCy Schubert char *
evbuffer_readline(struct evbuffer * buffer)14682b15cb3dSCy Schubert evbuffer_readline(struct evbuffer *buffer)
14692b15cb3dSCy Schubert {
14702b15cb3dSCy Schubert return evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY);
14712b15cb3dSCy Schubert }
14722b15cb3dSCy Schubert
14732b15cb3dSCy Schubert static inline ev_ssize_t
evbuffer_strchr(struct evbuffer_ptr * it,const char chr)14742b15cb3dSCy Schubert evbuffer_strchr(struct evbuffer_ptr *it, const char chr)
14752b15cb3dSCy Schubert {
14762b15cb3dSCy Schubert struct evbuffer_chain *chain = it->internal_.chain;
14772b15cb3dSCy Schubert size_t i = it->internal_.pos_in_chain;
14782b15cb3dSCy Schubert while (chain != NULL) {
14792b15cb3dSCy Schubert char *buffer = (char *)chain->buffer + chain->misalign;
14802b15cb3dSCy Schubert char *cp = memchr(buffer+i, chr, chain->off-i);
14812b15cb3dSCy Schubert if (cp) {
14822b15cb3dSCy Schubert it->internal_.chain = chain;
14832b15cb3dSCy Schubert it->internal_.pos_in_chain = cp - buffer;
14842b15cb3dSCy Schubert it->pos += (cp - buffer - i);
14852b15cb3dSCy Schubert return it->pos;
14862b15cb3dSCy Schubert }
14872b15cb3dSCy Schubert it->pos += chain->off - i;
14882b15cb3dSCy Schubert i = 0;
14892b15cb3dSCy Schubert chain = chain->next;
14902b15cb3dSCy Schubert }
14912b15cb3dSCy Schubert
14922b15cb3dSCy Schubert return (-1);
14932b15cb3dSCy Schubert }
14942b15cb3dSCy Schubert
14952b15cb3dSCy Schubert static inline char *
find_eol_char(char * s,size_t len)14962b15cb3dSCy Schubert find_eol_char(char *s, size_t len)
14972b15cb3dSCy Schubert {
14982b15cb3dSCy Schubert #define CHUNK_SZ 128
14992b15cb3dSCy Schubert /* Lots of benchmarking found this approach to be faster in practice
15002b15cb3dSCy Schubert * than doing two memchrs over the whole buffer, doin a memchr on each
15012b15cb3dSCy Schubert * char of the buffer, or trying to emulate memchr by hand. */
15022b15cb3dSCy Schubert char *s_end, *cr, *lf;
15032b15cb3dSCy Schubert s_end = s+len;
15042b15cb3dSCy Schubert while (s < s_end) {
15052b15cb3dSCy Schubert size_t chunk = (s + CHUNK_SZ < s_end) ? CHUNK_SZ : (s_end - s);
15062b15cb3dSCy Schubert cr = memchr(s, '\r', chunk);
15072b15cb3dSCy Schubert lf = memchr(s, '\n', chunk);
15082b15cb3dSCy Schubert if (cr) {
15092b15cb3dSCy Schubert if (lf && lf < cr)
15102b15cb3dSCy Schubert return lf;
15112b15cb3dSCy Schubert return cr;
15122b15cb3dSCy Schubert } else if (lf) {
15132b15cb3dSCy Schubert return lf;
15142b15cb3dSCy Schubert }
15152b15cb3dSCy Schubert s += CHUNK_SZ;
15162b15cb3dSCy Schubert }
15172b15cb3dSCy Schubert
15182b15cb3dSCy Schubert return NULL;
15192b15cb3dSCy Schubert #undef CHUNK_SZ
15202b15cb3dSCy Schubert }
15212b15cb3dSCy Schubert
15222b15cb3dSCy Schubert static ev_ssize_t
evbuffer_find_eol_char(struct evbuffer_ptr * it)15232b15cb3dSCy Schubert evbuffer_find_eol_char(struct evbuffer_ptr *it)
15242b15cb3dSCy Schubert {
15252b15cb3dSCy Schubert struct evbuffer_chain *chain = it->internal_.chain;
15262b15cb3dSCy Schubert size_t i = it->internal_.pos_in_chain;
15272b15cb3dSCy Schubert while (chain != NULL) {
15282b15cb3dSCy Schubert char *buffer = (char *)chain->buffer + chain->misalign;
15292b15cb3dSCy Schubert char *cp = find_eol_char(buffer+i, chain->off-i);
15302b15cb3dSCy Schubert if (cp) {
15312b15cb3dSCy Schubert it->internal_.chain = chain;
15322b15cb3dSCy Schubert it->internal_.pos_in_chain = cp - buffer;
15332b15cb3dSCy Schubert it->pos += (cp - buffer) - i;
15342b15cb3dSCy Schubert return it->pos;
15352b15cb3dSCy Schubert }
15362b15cb3dSCy Schubert it->pos += chain->off - i;
15372b15cb3dSCy Schubert i = 0;
15382b15cb3dSCy Schubert chain = chain->next;
15392b15cb3dSCy Schubert }
15402b15cb3dSCy Schubert
15412b15cb3dSCy Schubert return (-1);
15422b15cb3dSCy Schubert }
15432b15cb3dSCy Schubert
1544*a466cc55SCy Schubert static inline size_t
evbuffer_strspn(struct evbuffer_ptr * ptr,const char * chrset)15452b15cb3dSCy Schubert evbuffer_strspn(
15462b15cb3dSCy Schubert struct evbuffer_ptr *ptr, const char *chrset)
15472b15cb3dSCy Schubert {
1548*a466cc55SCy Schubert size_t count = 0;
15492b15cb3dSCy Schubert struct evbuffer_chain *chain = ptr->internal_.chain;
15502b15cb3dSCy Schubert size_t i = ptr->internal_.pos_in_chain;
15512b15cb3dSCy Schubert
15522b15cb3dSCy Schubert if (!chain)
15532b15cb3dSCy Schubert return 0;
15542b15cb3dSCy Schubert
15552b15cb3dSCy Schubert while (1) {
15562b15cb3dSCy Schubert char *buffer = (char *)chain->buffer + chain->misalign;
15572b15cb3dSCy Schubert for (; i < chain->off; ++i) {
15582b15cb3dSCy Schubert const char *p = chrset;
15592b15cb3dSCy Schubert while (*p) {
15602b15cb3dSCy Schubert if (buffer[i] == *p++)
15612b15cb3dSCy Schubert goto next;
15622b15cb3dSCy Schubert }
15632b15cb3dSCy Schubert ptr->internal_.chain = chain;
15642b15cb3dSCy Schubert ptr->internal_.pos_in_chain = i;
15652b15cb3dSCy Schubert ptr->pos += count;
15662b15cb3dSCy Schubert return count;
15672b15cb3dSCy Schubert next:
15682b15cb3dSCy Schubert ++count;
15692b15cb3dSCy Schubert }
15702b15cb3dSCy Schubert i = 0;
15712b15cb3dSCy Schubert
15722b15cb3dSCy Schubert if (! chain->next) {
15732b15cb3dSCy Schubert ptr->internal_.chain = chain;
15742b15cb3dSCy Schubert ptr->internal_.pos_in_chain = i;
15752b15cb3dSCy Schubert ptr->pos += count;
15762b15cb3dSCy Schubert return count;
15772b15cb3dSCy Schubert }
15782b15cb3dSCy Schubert
15792b15cb3dSCy Schubert chain = chain->next;
15802b15cb3dSCy Schubert }
15812b15cb3dSCy Schubert }
15822b15cb3dSCy Schubert
15832b15cb3dSCy Schubert
15842b15cb3dSCy Schubert static inline int
evbuffer_getchr(struct evbuffer_ptr * it)15852b15cb3dSCy Schubert evbuffer_getchr(struct evbuffer_ptr *it)
15862b15cb3dSCy Schubert {
15872b15cb3dSCy Schubert struct evbuffer_chain *chain = it->internal_.chain;
15882b15cb3dSCy Schubert size_t off = it->internal_.pos_in_chain;
15892b15cb3dSCy Schubert
15902b15cb3dSCy Schubert if (chain == NULL)
15912b15cb3dSCy Schubert return -1;
15922b15cb3dSCy Schubert
15932b15cb3dSCy Schubert return (unsigned char)chain->buffer[chain->misalign + off];
15942b15cb3dSCy Schubert }
15952b15cb3dSCy Schubert
15962b15cb3dSCy Schubert struct evbuffer_ptr
evbuffer_search_eol(struct evbuffer * buffer,struct evbuffer_ptr * start,size_t * eol_len_out,enum evbuffer_eol_style eol_style)15972b15cb3dSCy Schubert evbuffer_search_eol(struct evbuffer *buffer,
15982b15cb3dSCy Schubert struct evbuffer_ptr *start, size_t *eol_len_out,
15992b15cb3dSCy Schubert enum evbuffer_eol_style eol_style)
16002b15cb3dSCy Schubert {
16012b15cb3dSCy Schubert struct evbuffer_ptr it, it2;
16022b15cb3dSCy Schubert size_t extra_drain = 0;
16032b15cb3dSCy Schubert int ok = 0;
16042b15cb3dSCy Schubert
16052b15cb3dSCy Schubert /* Avoid locking in trivial edge cases */
16062b15cb3dSCy Schubert if (start && start->internal_.chain == NULL) {
16072b15cb3dSCy Schubert PTR_NOT_FOUND(&it);
16082b15cb3dSCy Schubert if (eol_len_out)
16092b15cb3dSCy Schubert *eol_len_out = extra_drain;
16102b15cb3dSCy Schubert return it;
16112b15cb3dSCy Schubert }
16122b15cb3dSCy Schubert
16132b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
16142b15cb3dSCy Schubert
16152b15cb3dSCy Schubert if (start) {
16162b15cb3dSCy Schubert memcpy(&it, start, sizeof(it));
16172b15cb3dSCy Schubert } else {
16182b15cb3dSCy Schubert it.pos = 0;
16192b15cb3dSCy Schubert it.internal_.chain = buffer->first;
16202b15cb3dSCy Schubert it.internal_.pos_in_chain = 0;
16212b15cb3dSCy Schubert }
16222b15cb3dSCy Schubert
16232b15cb3dSCy Schubert /* the eol_style determines our first stop character and how many
16242b15cb3dSCy Schubert * characters we are going to drain afterwards. */
16252b15cb3dSCy Schubert switch (eol_style) {
16262b15cb3dSCy Schubert case EVBUFFER_EOL_ANY:
16272b15cb3dSCy Schubert if (evbuffer_find_eol_char(&it) < 0)
16282b15cb3dSCy Schubert goto done;
16292b15cb3dSCy Schubert memcpy(&it2, &it, sizeof(it));
16302b15cb3dSCy Schubert extra_drain = evbuffer_strspn(&it2, "\r\n");
16312b15cb3dSCy Schubert break;
16322b15cb3dSCy Schubert case EVBUFFER_EOL_CRLF_STRICT: {
16332b15cb3dSCy Schubert it = evbuffer_search(buffer, "\r\n", 2, &it);
16342b15cb3dSCy Schubert if (it.pos < 0)
16352b15cb3dSCy Schubert goto done;
16362b15cb3dSCy Schubert extra_drain = 2;
16372b15cb3dSCy Schubert break;
16382b15cb3dSCy Schubert }
16392b15cb3dSCy Schubert case EVBUFFER_EOL_CRLF: {
16402b15cb3dSCy Schubert ev_ssize_t start_pos = it.pos;
16412b15cb3dSCy Schubert /* Look for a LF ... */
16422b15cb3dSCy Schubert if (evbuffer_strchr(&it, '\n') < 0)
16432b15cb3dSCy Schubert goto done;
16442b15cb3dSCy Schubert extra_drain = 1;
16452b15cb3dSCy Schubert /* ... optionally preceeded by a CR. */
16462b15cb3dSCy Schubert if (it.pos == start_pos)
16472b15cb3dSCy Schubert break; /* If the first character is \n, don't back up */
16482b15cb3dSCy Schubert /* This potentially does an extra linear walk over the first
16492b15cb3dSCy Schubert * few chains. Probably, that's not too expensive unless you
16502b15cb3dSCy Schubert * have a really pathological setup. */
16512b15cb3dSCy Schubert memcpy(&it2, &it, sizeof(it));
16522b15cb3dSCy Schubert if (evbuffer_ptr_subtract(buffer, &it2, 1)<0)
16532b15cb3dSCy Schubert break;
16542b15cb3dSCy Schubert if (evbuffer_getchr(&it2) == '\r') {
16552b15cb3dSCy Schubert memcpy(&it, &it2, sizeof(it));
16562b15cb3dSCy Schubert extra_drain = 2;
16572b15cb3dSCy Schubert }
16582b15cb3dSCy Schubert break;
16592b15cb3dSCy Schubert }
16602b15cb3dSCy Schubert case EVBUFFER_EOL_LF:
16612b15cb3dSCy Schubert if (evbuffer_strchr(&it, '\n') < 0)
16622b15cb3dSCy Schubert goto done;
16632b15cb3dSCy Schubert extra_drain = 1;
16642b15cb3dSCy Schubert break;
16652b15cb3dSCy Schubert case EVBUFFER_EOL_NUL:
16662b15cb3dSCy Schubert if (evbuffer_strchr(&it, '\0') < 0)
16672b15cb3dSCy Schubert goto done;
16682b15cb3dSCy Schubert extra_drain = 1;
16692b15cb3dSCy Schubert break;
16702b15cb3dSCy Schubert default:
16712b15cb3dSCy Schubert goto done;
16722b15cb3dSCy Schubert }
16732b15cb3dSCy Schubert
16742b15cb3dSCy Schubert ok = 1;
16752b15cb3dSCy Schubert done:
16762b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
16772b15cb3dSCy Schubert
16782b15cb3dSCy Schubert if (!ok)
16792b15cb3dSCy Schubert PTR_NOT_FOUND(&it);
16802b15cb3dSCy Schubert if (eol_len_out)
16812b15cb3dSCy Schubert *eol_len_out = extra_drain;
16822b15cb3dSCy Schubert
16832b15cb3dSCy Schubert return it;
16842b15cb3dSCy Schubert }
16852b15cb3dSCy Schubert
16862b15cb3dSCy Schubert char *
evbuffer_readln(struct evbuffer * buffer,size_t * n_read_out,enum evbuffer_eol_style eol_style)16872b15cb3dSCy Schubert evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
16882b15cb3dSCy Schubert enum evbuffer_eol_style eol_style)
16892b15cb3dSCy Schubert {
16902b15cb3dSCy Schubert struct evbuffer_ptr it;
16912b15cb3dSCy Schubert char *line;
16922b15cb3dSCy Schubert size_t n_to_copy=0, extra_drain=0;
16932b15cb3dSCy Schubert char *result = NULL;
16942b15cb3dSCy Schubert
16952b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
16962b15cb3dSCy Schubert
16972b15cb3dSCy Schubert if (buffer->freeze_start) {
16982b15cb3dSCy Schubert goto done;
16992b15cb3dSCy Schubert }
17002b15cb3dSCy Schubert
17012b15cb3dSCy Schubert it = evbuffer_search_eol(buffer, NULL, &extra_drain, eol_style);
17022b15cb3dSCy Schubert if (it.pos < 0)
17032b15cb3dSCy Schubert goto done;
17042b15cb3dSCy Schubert n_to_copy = it.pos;
17052b15cb3dSCy Schubert
17062b15cb3dSCy Schubert if ((line = mm_malloc(n_to_copy+1)) == NULL) {
17072b15cb3dSCy Schubert event_warn("%s: out of memory", __func__);
17082b15cb3dSCy Schubert goto done;
17092b15cb3dSCy Schubert }
17102b15cb3dSCy Schubert
17112b15cb3dSCy Schubert evbuffer_remove(buffer, line, n_to_copy);
17122b15cb3dSCy Schubert line[n_to_copy] = '\0';
17132b15cb3dSCy Schubert
17142b15cb3dSCy Schubert evbuffer_drain(buffer, extra_drain);
17152b15cb3dSCy Schubert result = line;
17162b15cb3dSCy Schubert done:
17172b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
17182b15cb3dSCy Schubert
17192b15cb3dSCy Schubert if (n_read_out)
17202b15cb3dSCy Schubert *n_read_out = result ? n_to_copy : 0;
17212b15cb3dSCy Schubert
17222b15cb3dSCy Schubert return result;
17232b15cb3dSCy Schubert }
17242b15cb3dSCy Schubert
17252b15cb3dSCy Schubert #define EVBUFFER_CHAIN_MAX_AUTO_SIZE 4096
17262b15cb3dSCy Schubert
17272b15cb3dSCy Schubert /* Adds data to an event buffer */
17282b15cb3dSCy Schubert
17292b15cb3dSCy Schubert int
evbuffer_add(struct evbuffer * buf,const void * data_in,size_t datlen)17302b15cb3dSCy Schubert evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
17312b15cb3dSCy Schubert {
17322b15cb3dSCy Schubert struct evbuffer_chain *chain, *tmp;
17332b15cb3dSCy Schubert const unsigned char *data = data_in;
17342b15cb3dSCy Schubert size_t remain, to_alloc;
17352b15cb3dSCy Schubert int result = -1;
17362b15cb3dSCy Schubert
17372b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
17382b15cb3dSCy Schubert
17392b15cb3dSCy Schubert if (buf->freeze_end) {
17402b15cb3dSCy Schubert goto done;
17412b15cb3dSCy Schubert }
1742a25439b6SCy Schubert /* Prevent buf->total_len overflow */
1743a25439b6SCy Schubert if (datlen > EV_SIZE_MAX - buf->total_len) {
1744a25439b6SCy Schubert goto done;
1745a25439b6SCy Schubert }
17462b15cb3dSCy Schubert
1747*a466cc55SCy Schubert if (*buf->last_with_datap == NULL) {
17482b15cb3dSCy Schubert chain = buf->last;
1749*a466cc55SCy Schubert } else {
1750*a466cc55SCy Schubert chain = *buf->last_with_datap;
1751*a466cc55SCy Schubert }
17522b15cb3dSCy Schubert
17532b15cb3dSCy Schubert /* If there are no chains allocated for this buffer, allocate one
17542b15cb3dSCy Schubert * big enough to hold all the data. */
17552b15cb3dSCy Schubert if (chain == NULL) {
17562b15cb3dSCy Schubert chain = evbuffer_chain_new(datlen);
17572b15cb3dSCy Schubert if (!chain)
17582b15cb3dSCy Schubert goto done;
17592b15cb3dSCy Schubert evbuffer_chain_insert(buf, chain);
17602b15cb3dSCy Schubert }
17612b15cb3dSCy Schubert
17622b15cb3dSCy Schubert if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
1763a25439b6SCy Schubert /* Always true for mutable buffers */
1764a25439b6SCy Schubert EVUTIL_ASSERT(chain->misalign >= 0 &&
1765a25439b6SCy Schubert (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
1766a25439b6SCy Schubert remain = chain->buffer_len - (size_t)chain->misalign - chain->off;
17672b15cb3dSCy Schubert if (remain >= datlen) {
17682b15cb3dSCy Schubert /* there's enough space to hold all the data in the
17692b15cb3dSCy Schubert * current last chain */
17702b15cb3dSCy Schubert memcpy(chain->buffer + chain->misalign + chain->off,
17712b15cb3dSCy Schubert data, datlen);
17722b15cb3dSCy Schubert chain->off += datlen;
17732b15cb3dSCy Schubert buf->total_len += datlen;
17742b15cb3dSCy Schubert buf->n_add_for_cb += datlen;
17752b15cb3dSCy Schubert goto out;
17762b15cb3dSCy Schubert } else if (!CHAIN_PINNED(chain) &&
17772b15cb3dSCy Schubert evbuffer_chain_should_realign(chain, datlen)) {
17782b15cb3dSCy Schubert /* we can fit the data into the misalignment */
17792b15cb3dSCy Schubert evbuffer_chain_align(chain);
17802b15cb3dSCy Schubert
17812b15cb3dSCy Schubert memcpy(chain->buffer + chain->off, data, datlen);
17822b15cb3dSCy Schubert chain->off += datlen;
17832b15cb3dSCy Schubert buf->total_len += datlen;
17842b15cb3dSCy Schubert buf->n_add_for_cb += datlen;
17852b15cb3dSCy Schubert goto out;
17862b15cb3dSCy Schubert }
17872b15cb3dSCy Schubert } else {
17882b15cb3dSCy Schubert /* we cannot write any data to the last chain */
17892b15cb3dSCy Schubert remain = 0;
17902b15cb3dSCy Schubert }
17912b15cb3dSCy Schubert
17922b15cb3dSCy Schubert /* we need to add another chain */
17932b15cb3dSCy Schubert to_alloc = chain->buffer_len;
17942b15cb3dSCy Schubert if (to_alloc <= EVBUFFER_CHAIN_MAX_AUTO_SIZE/2)
17952b15cb3dSCy Schubert to_alloc <<= 1;
17962b15cb3dSCy Schubert if (datlen > to_alloc)
17972b15cb3dSCy Schubert to_alloc = datlen;
17982b15cb3dSCy Schubert tmp = evbuffer_chain_new(to_alloc);
17992b15cb3dSCy Schubert if (tmp == NULL)
18002b15cb3dSCy Schubert goto done;
18012b15cb3dSCy Schubert
18022b15cb3dSCy Schubert if (remain) {
18032b15cb3dSCy Schubert memcpy(chain->buffer + chain->misalign + chain->off,
18042b15cb3dSCy Schubert data, remain);
18052b15cb3dSCy Schubert chain->off += remain;
18062b15cb3dSCy Schubert buf->total_len += remain;
18072b15cb3dSCy Schubert buf->n_add_for_cb += remain;
18082b15cb3dSCy Schubert }
18092b15cb3dSCy Schubert
18102b15cb3dSCy Schubert data += remain;
18112b15cb3dSCy Schubert datlen -= remain;
18122b15cb3dSCy Schubert
18132b15cb3dSCy Schubert memcpy(tmp->buffer, data, datlen);
18142b15cb3dSCy Schubert tmp->off = datlen;
18152b15cb3dSCy Schubert evbuffer_chain_insert(buf, tmp);
18162b15cb3dSCy Schubert buf->n_add_for_cb += datlen;
18172b15cb3dSCy Schubert
18182b15cb3dSCy Schubert out:
18192b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
18202b15cb3dSCy Schubert result = 0;
18212b15cb3dSCy Schubert done:
18222b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
18232b15cb3dSCy Schubert return result;
18242b15cb3dSCy Schubert }
18252b15cb3dSCy Schubert
18262b15cb3dSCy Schubert int
evbuffer_prepend(struct evbuffer * buf,const void * data,size_t datlen)18272b15cb3dSCy Schubert evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
18282b15cb3dSCy Schubert {
18292b15cb3dSCy Schubert struct evbuffer_chain *chain, *tmp;
18302b15cb3dSCy Schubert int result = -1;
18312b15cb3dSCy Schubert
18322b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
18332b15cb3dSCy Schubert
1834*a466cc55SCy Schubert if (datlen == 0) {
1835*a466cc55SCy Schubert result = 0;
1836*a466cc55SCy Schubert goto done;
1837*a466cc55SCy Schubert }
18382b15cb3dSCy Schubert if (buf->freeze_start) {
18392b15cb3dSCy Schubert goto done;
18402b15cb3dSCy Schubert }
1841a25439b6SCy Schubert if (datlen > EV_SIZE_MAX - buf->total_len) {
1842a25439b6SCy Schubert goto done;
1843a25439b6SCy Schubert }
18442b15cb3dSCy Schubert
18452b15cb3dSCy Schubert chain = buf->first;
18462b15cb3dSCy Schubert
18472b15cb3dSCy Schubert if (chain == NULL) {
18482b15cb3dSCy Schubert chain = evbuffer_chain_new(datlen);
18492b15cb3dSCy Schubert if (!chain)
18502b15cb3dSCy Schubert goto done;
18512b15cb3dSCy Schubert evbuffer_chain_insert(buf, chain);
18522b15cb3dSCy Schubert }
18532b15cb3dSCy Schubert
18542b15cb3dSCy Schubert /* we cannot touch immutable buffers */
18552b15cb3dSCy Schubert if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
1856a25439b6SCy Schubert /* Always true for mutable buffers */
1857a25439b6SCy Schubert EVUTIL_ASSERT(chain->misalign >= 0 &&
1858a25439b6SCy Schubert (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
1859a25439b6SCy Schubert
18602b15cb3dSCy Schubert /* If this chain is empty, we can treat it as
18612b15cb3dSCy Schubert * 'empty at the beginning' rather than 'empty at the end' */
18622b15cb3dSCy Schubert if (chain->off == 0)
18632b15cb3dSCy Schubert chain->misalign = chain->buffer_len;
18642b15cb3dSCy Schubert
18652b15cb3dSCy Schubert if ((size_t)chain->misalign >= datlen) {
18662b15cb3dSCy Schubert /* we have enough space to fit everything */
18672b15cb3dSCy Schubert memcpy(chain->buffer + chain->misalign - datlen,
18682b15cb3dSCy Schubert data, datlen);
18692b15cb3dSCy Schubert chain->off += datlen;
18702b15cb3dSCy Schubert chain->misalign -= datlen;
18712b15cb3dSCy Schubert buf->total_len += datlen;
18722b15cb3dSCy Schubert buf->n_add_for_cb += datlen;
18732b15cb3dSCy Schubert goto out;
18742b15cb3dSCy Schubert } else if (chain->misalign) {
18752b15cb3dSCy Schubert /* we can only fit some of the data. */
18762b15cb3dSCy Schubert memcpy(chain->buffer,
18772b15cb3dSCy Schubert (char*)data + datlen - chain->misalign,
18782b15cb3dSCy Schubert (size_t)chain->misalign);
18792b15cb3dSCy Schubert chain->off += (size_t)chain->misalign;
18802b15cb3dSCy Schubert buf->total_len += (size_t)chain->misalign;
18812b15cb3dSCy Schubert buf->n_add_for_cb += (size_t)chain->misalign;
18822b15cb3dSCy Schubert datlen -= (size_t)chain->misalign;
18832b15cb3dSCy Schubert chain->misalign = 0;
18842b15cb3dSCy Schubert }
18852b15cb3dSCy Schubert }
18862b15cb3dSCy Schubert
18872b15cb3dSCy Schubert /* we need to add another chain */
18882b15cb3dSCy Schubert if ((tmp = evbuffer_chain_new(datlen)) == NULL)
18892b15cb3dSCy Schubert goto done;
18902b15cb3dSCy Schubert buf->first = tmp;
1891*a466cc55SCy Schubert if (buf->last_with_datap == &buf->first && chain->off)
18922b15cb3dSCy Schubert buf->last_with_datap = &tmp->next;
18932b15cb3dSCy Schubert
18942b15cb3dSCy Schubert tmp->next = chain;
18952b15cb3dSCy Schubert
18962b15cb3dSCy Schubert tmp->off = datlen;
1897a25439b6SCy Schubert EVUTIL_ASSERT(datlen <= tmp->buffer_len);
18982b15cb3dSCy Schubert tmp->misalign = tmp->buffer_len - datlen;
18992b15cb3dSCy Schubert
19002b15cb3dSCy Schubert memcpy(tmp->buffer + tmp->misalign, data, datlen);
19012b15cb3dSCy Schubert buf->total_len += datlen;
1902*a466cc55SCy Schubert buf->n_add_for_cb += datlen;
19032b15cb3dSCy Schubert
19042b15cb3dSCy Schubert out:
19052b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
19062b15cb3dSCy Schubert result = 0;
19072b15cb3dSCy Schubert done:
19082b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
19092b15cb3dSCy Schubert return result;
19102b15cb3dSCy Schubert }
19112b15cb3dSCy Schubert
19122b15cb3dSCy Schubert /** Helper: realigns the memory in chain->buffer so that misalign is 0. */
19132b15cb3dSCy Schubert static void
evbuffer_chain_align(struct evbuffer_chain * chain)19142b15cb3dSCy Schubert evbuffer_chain_align(struct evbuffer_chain *chain)
19152b15cb3dSCy Schubert {
19162b15cb3dSCy Schubert EVUTIL_ASSERT(!(chain->flags & EVBUFFER_IMMUTABLE));
19172b15cb3dSCy Schubert EVUTIL_ASSERT(!(chain->flags & EVBUFFER_MEM_PINNED_ANY));
19182b15cb3dSCy Schubert memmove(chain->buffer, chain->buffer + chain->misalign, chain->off);
19192b15cb3dSCy Schubert chain->misalign = 0;
19202b15cb3dSCy Schubert }
19212b15cb3dSCy Schubert
19222b15cb3dSCy Schubert #define MAX_TO_COPY_IN_EXPAND 4096
19232b15cb3dSCy Schubert #define MAX_TO_REALIGN_IN_EXPAND 2048
19242b15cb3dSCy Schubert
19252b15cb3dSCy Schubert /** Helper: return true iff we should realign chain to fit datalen bytes of
19262b15cb3dSCy Schubert data in it. */
19272b15cb3dSCy Schubert static int
evbuffer_chain_should_realign(struct evbuffer_chain * chain,size_t datlen)19282b15cb3dSCy Schubert evbuffer_chain_should_realign(struct evbuffer_chain *chain,
19292b15cb3dSCy Schubert size_t datlen)
19302b15cb3dSCy Schubert {
19312b15cb3dSCy Schubert return chain->buffer_len - chain->off >= datlen &&
19322b15cb3dSCy Schubert (chain->off < chain->buffer_len / 2) &&
19332b15cb3dSCy Schubert (chain->off <= MAX_TO_REALIGN_IN_EXPAND);
19342b15cb3dSCy Schubert }
19352b15cb3dSCy Schubert
19362b15cb3dSCy Schubert /* Expands the available space in the event buffer to at least datlen, all in
19372b15cb3dSCy Schubert * a single chunk. Return that chunk. */
19382b15cb3dSCy Schubert static struct evbuffer_chain *
evbuffer_expand_singlechain(struct evbuffer * buf,size_t datlen)19392b15cb3dSCy Schubert evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
19402b15cb3dSCy Schubert {
19412b15cb3dSCy Schubert struct evbuffer_chain *chain, **chainp;
19422b15cb3dSCy Schubert struct evbuffer_chain *result = NULL;
19432b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buf);
19442b15cb3dSCy Schubert
19452b15cb3dSCy Schubert chainp = buf->last_with_datap;
19462b15cb3dSCy Schubert
19472b15cb3dSCy Schubert /* XXX If *chainp is no longer writeable, but has enough space in its
19482b15cb3dSCy Schubert * misalign, this might be a bad idea: we could still use *chainp, not
19492b15cb3dSCy Schubert * (*chainp)->next. */
19502b15cb3dSCy Schubert if (*chainp && CHAIN_SPACE_LEN(*chainp) == 0)
19512b15cb3dSCy Schubert chainp = &(*chainp)->next;
19522b15cb3dSCy Schubert
19532b15cb3dSCy Schubert /* 'chain' now points to the first chain with writable space (if any)
19542b15cb3dSCy Schubert * We will either use it, realign it, replace it, or resize it. */
19552b15cb3dSCy Schubert chain = *chainp;
19562b15cb3dSCy Schubert
19572b15cb3dSCy Schubert if (chain == NULL ||
19582b15cb3dSCy Schubert (chain->flags & (EVBUFFER_IMMUTABLE|EVBUFFER_MEM_PINNED_ANY))) {
19592b15cb3dSCy Schubert /* We can't use the last_with_data chain at all. Just add a
19602b15cb3dSCy Schubert * new one that's big enough. */
19612b15cb3dSCy Schubert goto insert_new;
19622b15cb3dSCy Schubert }
19632b15cb3dSCy Schubert
19642b15cb3dSCy Schubert /* If we can fit all the data, then we don't have to do anything */
19652b15cb3dSCy Schubert if (CHAIN_SPACE_LEN(chain) >= datlen) {
19662b15cb3dSCy Schubert result = chain;
19672b15cb3dSCy Schubert goto ok;
19682b15cb3dSCy Schubert }
19692b15cb3dSCy Schubert
19702b15cb3dSCy Schubert /* If the chain is completely empty, just replace it by adding a new
19712b15cb3dSCy Schubert * empty chain. */
19722b15cb3dSCy Schubert if (chain->off == 0) {
19732b15cb3dSCy Schubert goto insert_new;
19742b15cb3dSCy Schubert }
19752b15cb3dSCy Schubert
19762b15cb3dSCy Schubert /* If the misalignment plus the remaining space fulfills our data
19772b15cb3dSCy Schubert * needs, we could just force an alignment to happen. Afterwards, we
19782b15cb3dSCy Schubert * have enough space. But only do this if we're saving a lot of space
19792b15cb3dSCy Schubert * and not moving too much data. Otherwise the space savings are
19802b15cb3dSCy Schubert * probably offset by the time lost in copying.
19812b15cb3dSCy Schubert */
19822b15cb3dSCy Schubert if (evbuffer_chain_should_realign(chain, datlen)) {
19832b15cb3dSCy Schubert evbuffer_chain_align(chain);
19842b15cb3dSCy Schubert result = chain;
19852b15cb3dSCy Schubert goto ok;
19862b15cb3dSCy Schubert }
19872b15cb3dSCy Schubert
19882b15cb3dSCy Schubert /* At this point, we can either resize the last chunk with space in
19892b15cb3dSCy Schubert * it, use the next chunk after it, or If we add a new chunk, we waste
19902b15cb3dSCy Schubert * CHAIN_SPACE_LEN(chain) bytes in the former last chunk. If we
19912b15cb3dSCy Schubert * resize, we have to copy chain->off bytes.
19922b15cb3dSCy Schubert */
19932b15cb3dSCy Schubert
19942b15cb3dSCy Schubert /* Would expanding this chunk be affordable and worthwhile? */
19952b15cb3dSCy Schubert if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
1996a25439b6SCy Schubert chain->off > MAX_TO_COPY_IN_EXPAND ||
1997*a466cc55SCy Schubert datlen >= (EVBUFFER_CHAIN_MAX - chain->off)) {
19982b15cb3dSCy Schubert /* It's not worth resizing this chain. Can the next one be
19992b15cb3dSCy Schubert * used? */
20002b15cb3dSCy Schubert if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
20012b15cb3dSCy Schubert /* Yes, we can just use the next chain (which should
20022b15cb3dSCy Schubert * be empty. */
20032b15cb3dSCy Schubert result = chain->next;
20042b15cb3dSCy Schubert goto ok;
20052b15cb3dSCy Schubert } else {
20062b15cb3dSCy Schubert /* No; append a new chain (which will free all
20072b15cb3dSCy Schubert * terminal empty chains.) */
20082b15cb3dSCy Schubert goto insert_new;
20092b15cb3dSCy Schubert }
20102b15cb3dSCy Schubert } else {
20112b15cb3dSCy Schubert /* Okay, we're going to try to resize this chain: Not doing so
20122b15cb3dSCy Schubert * would waste at least 1/8 of its current allocation, and we
20132b15cb3dSCy Schubert * can do so without having to copy more than
20142b15cb3dSCy Schubert * MAX_TO_COPY_IN_EXPAND bytes. */
20152b15cb3dSCy Schubert /* figure out how much space we need */
20162b15cb3dSCy Schubert size_t length = chain->off + datlen;
20172b15cb3dSCy Schubert struct evbuffer_chain *tmp = evbuffer_chain_new(length);
20182b15cb3dSCy Schubert if (tmp == NULL)
20192b15cb3dSCy Schubert goto err;
20202b15cb3dSCy Schubert
20212b15cb3dSCy Schubert /* copy the data over that we had so far */
20222b15cb3dSCy Schubert tmp->off = chain->off;
20232b15cb3dSCy Schubert memcpy(tmp->buffer, chain->buffer + chain->misalign,
20242b15cb3dSCy Schubert chain->off);
20252b15cb3dSCy Schubert /* fix up the list */
20262b15cb3dSCy Schubert EVUTIL_ASSERT(*chainp == chain);
20272b15cb3dSCy Schubert result = *chainp = tmp;
20282b15cb3dSCy Schubert
20292b15cb3dSCy Schubert if (buf->last == chain)
20302b15cb3dSCy Schubert buf->last = tmp;
20312b15cb3dSCy Schubert
20322b15cb3dSCy Schubert tmp->next = chain->next;
20332b15cb3dSCy Schubert evbuffer_chain_free(chain);
20342b15cb3dSCy Schubert goto ok;
20352b15cb3dSCy Schubert }
20362b15cb3dSCy Schubert
20372b15cb3dSCy Schubert insert_new:
20382b15cb3dSCy Schubert result = evbuffer_chain_insert_new(buf, datlen);
20392b15cb3dSCy Schubert if (!result)
20402b15cb3dSCy Schubert goto err;
20412b15cb3dSCy Schubert ok:
20422b15cb3dSCy Schubert EVUTIL_ASSERT(result);
20432b15cb3dSCy Schubert EVUTIL_ASSERT(CHAIN_SPACE_LEN(result) >= datlen);
20442b15cb3dSCy Schubert err:
20452b15cb3dSCy Schubert return result;
20462b15cb3dSCy Schubert }
20472b15cb3dSCy Schubert
20482b15cb3dSCy Schubert /* Make sure that datlen bytes are available for writing in the last n
20492b15cb3dSCy Schubert * chains. Never copies or moves data. */
20502b15cb3dSCy Schubert int
evbuffer_expand_fast_(struct evbuffer * buf,size_t datlen,int n)20512b15cb3dSCy Schubert evbuffer_expand_fast_(struct evbuffer *buf, size_t datlen, int n)
20522b15cb3dSCy Schubert {
20532b15cb3dSCy Schubert struct evbuffer_chain *chain = buf->last, *tmp, *next;
20542b15cb3dSCy Schubert size_t avail;
20552b15cb3dSCy Schubert int used;
20562b15cb3dSCy Schubert
20572b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buf);
20582b15cb3dSCy Schubert EVUTIL_ASSERT(n >= 2);
20592b15cb3dSCy Schubert
20602b15cb3dSCy Schubert if (chain == NULL || (chain->flags & EVBUFFER_IMMUTABLE)) {
20612b15cb3dSCy Schubert /* There is no last chunk, or we can't touch the last chunk.
20622b15cb3dSCy Schubert * Just add a new chunk. */
20632b15cb3dSCy Schubert chain = evbuffer_chain_new(datlen);
20642b15cb3dSCy Schubert if (chain == NULL)
20652b15cb3dSCy Schubert return (-1);
20662b15cb3dSCy Schubert
20672b15cb3dSCy Schubert evbuffer_chain_insert(buf, chain);
20682b15cb3dSCy Schubert return (0);
20692b15cb3dSCy Schubert }
20702b15cb3dSCy Schubert
20712b15cb3dSCy Schubert used = 0; /* number of chains we're using space in. */
20722b15cb3dSCy Schubert avail = 0; /* how much space they have. */
20732b15cb3dSCy Schubert /* How many bytes can we stick at the end of buffer as it is? Iterate
20742b15cb3dSCy Schubert * over the chains at the end of the buffer, tring to see how much
20752b15cb3dSCy Schubert * space we have in the first n. */
20762b15cb3dSCy Schubert for (chain = *buf->last_with_datap; chain; chain = chain->next) {
20772b15cb3dSCy Schubert if (chain->off) {
20782b15cb3dSCy Schubert size_t space = (size_t) CHAIN_SPACE_LEN(chain);
20792b15cb3dSCy Schubert EVUTIL_ASSERT(chain == *buf->last_with_datap);
20802b15cb3dSCy Schubert if (space) {
20812b15cb3dSCy Schubert avail += space;
20822b15cb3dSCy Schubert ++used;
20832b15cb3dSCy Schubert }
20842b15cb3dSCy Schubert } else {
20852b15cb3dSCy Schubert /* No data in chain; realign it. */
20862b15cb3dSCy Schubert chain->misalign = 0;
20872b15cb3dSCy Schubert avail += chain->buffer_len;
20882b15cb3dSCy Schubert ++used;
20892b15cb3dSCy Schubert }
20902b15cb3dSCy Schubert if (avail >= datlen) {
20912b15cb3dSCy Schubert /* There is already enough space. Just return */
20922b15cb3dSCy Schubert return (0);
20932b15cb3dSCy Schubert }
20942b15cb3dSCy Schubert if (used == n)
20952b15cb3dSCy Schubert break;
20962b15cb3dSCy Schubert }
20972b15cb3dSCy Schubert
20982b15cb3dSCy Schubert /* There wasn't enough space in the first n chains with space in
20992b15cb3dSCy Schubert * them. Either add a new chain with enough space, or replace all
21002b15cb3dSCy Schubert * empty chains with one that has enough space, depending on n. */
21012b15cb3dSCy Schubert if (used < n) {
21022b15cb3dSCy Schubert /* The loop ran off the end of the chains before it hit n
21032b15cb3dSCy Schubert * chains; we can add another. */
21042b15cb3dSCy Schubert EVUTIL_ASSERT(chain == NULL);
21052b15cb3dSCy Schubert
21062b15cb3dSCy Schubert tmp = evbuffer_chain_new(datlen - avail);
21072b15cb3dSCy Schubert if (tmp == NULL)
21082b15cb3dSCy Schubert return (-1);
21092b15cb3dSCy Schubert
21102b15cb3dSCy Schubert buf->last->next = tmp;
21112b15cb3dSCy Schubert buf->last = tmp;
21122b15cb3dSCy Schubert /* (we would only set last_with_data if we added the first
21132b15cb3dSCy Schubert * chain. But if the buffer had no chains, we would have
21142b15cb3dSCy Schubert * just allocated a new chain earlier) */
21152b15cb3dSCy Schubert return (0);
21162b15cb3dSCy Schubert } else {
21172b15cb3dSCy Schubert /* Nuke _all_ the empty chains. */
21182b15cb3dSCy Schubert int rmv_all = 0; /* True iff we removed last_with_data. */
21192b15cb3dSCy Schubert chain = *buf->last_with_datap;
21202b15cb3dSCy Schubert if (!chain->off) {
21212b15cb3dSCy Schubert EVUTIL_ASSERT(chain == buf->first);
21222b15cb3dSCy Schubert rmv_all = 1;
21232b15cb3dSCy Schubert avail = 0;
21242b15cb3dSCy Schubert } else {
2125a25439b6SCy Schubert /* can't overflow, since only mutable chains have
2126a25439b6SCy Schubert * huge misaligns. */
21272b15cb3dSCy Schubert avail = (size_t) CHAIN_SPACE_LEN(chain);
21282b15cb3dSCy Schubert chain = chain->next;
21292b15cb3dSCy Schubert }
21302b15cb3dSCy Schubert
21312b15cb3dSCy Schubert
21322b15cb3dSCy Schubert for (; chain; chain = next) {
21332b15cb3dSCy Schubert next = chain->next;
21342b15cb3dSCy Schubert EVUTIL_ASSERT(chain->off == 0);
21352b15cb3dSCy Schubert evbuffer_chain_free(chain);
21362b15cb3dSCy Schubert }
2137a25439b6SCy Schubert EVUTIL_ASSERT(datlen >= avail);
21382b15cb3dSCy Schubert tmp = evbuffer_chain_new(datlen - avail);
21392b15cb3dSCy Schubert if (tmp == NULL) {
21402b15cb3dSCy Schubert if (rmv_all) {
21412b15cb3dSCy Schubert ZERO_CHAIN(buf);
21422b15cb3dSCy Schubert } else {
21432b15cb3dSCy Schubert buf->last = *buf->last_with_datap;
21442b15cb3dSCy Schubert (*buf->last_with_datap)->next = NULL;
21452b15cb3dSCy Schubert }
21462b15cb3dSCy Schubert return (-1);
21472b15cb3dSCy Schubert }
21482b15cb3dSCy Schubert
21492b15cb3dSCy Schubert if (rmv_all) {
21502b15cb3dSCy Schubert buf->first = buf->last = tmp;
21512b15cb3dSCy Schubert buf->last_with_datap = &buf->first;
21522b15cb3dSCy Schubert } else {
21532b15cb3dSCy Schubert (*buf->last_with_datap)->next = tmp;
21542b15cb3dSCy Schubert buf->last = tmp;
21552b15cb3dSCy Schubert }
21562b15cb3dSCy Schubert return (0);
21572b15cb3dSCy Schubert }
21582b15cb3dSCy Schubert }
21592b15cb3dSCy Schubert
21602b15cb3dSCy Schubert int
evbuffer_expand(struct evbuffer * buf,size_t datlen)21612b15cb3dSCy Schubert evbuffer_expand(struct evbuffer *buf, size_t datlen)
21622b15cb3dSCy Schubert {
21632b15cb3dSCy Schubert struct evbuffer_chain *chain;
21642b15cb3dSCy Schubert
21652b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
21662b15cb3dSCy Schubert chain = evbuffer_expand_singlechain(buf, datlen);
21672b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
21682b15cb3dSCy Schubert return chain ? 0 : -1;
21692b15cb3dSCy Schubert }
21702b15cb3dSCy Schubert
21712b15cb3dSCy Schubert /*
21722b15cb3dSCy Schubert * Reads data from a file descriptor into a buffer.
21732b15cb3dSCy Schubert */
21742b15cb3dSCy Schubert
21752b15cb3dSCy Schubert #if defined(EVENT__HAVE_SYS_UIO_H) || defined(_WIN32)
21762b15cb3dSCy Schubert #define USE_IOVEC_IMPL
21772b15cb3dSCy Schubert #endif
21782b15cb3dSCy Schubert
21792b15cb3dSCy Schubert #ifdef USE_IOVEC_IMPL
21802b15cb3dSCy Schubert
21812b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_UIO_H
21822b15cb3dSCy Schubert /* number of iovec we use for writev, fragmentation is going to determine
21832b15cb3dSCy Schubert * how much we end up writing */
21842b15cb3dSCy Schubert
21852b15cb3dSCy Schubert #define DEFAULT_WRITE_IOVEC 128
21862b15cb3dSCy Schubert
21872b15cb3dSCy Schubert #if defined(UIO_MAXIOV) && UIO_MAXIOV < DEFAULT_WRITE_IOVEC
21882b15cb3dSCy Schubert #define NUM_WRITE_IOVEC UIO_MAXIOV
21892b15cb3dSCy Schubert #elif defined(IOV_MAX) && IOV_MAX < DEFAULT_WRITE_IOVEC
21902b15cb3dSCy Schubert #define NUM_WRITE_IOVEC IOV_MAX
21912b15cb3dSCy Schubert #else
21922b15cb3dSCy Schubert #define NUM_WRITE_IOVEC DEFAULT_WRITE_IOVEC
21932b15cb3dSCy Schubert #endif
21942b15cb3dSCy Schubert
21952b15cb3dSCy Schubert #define IOV_TYPE struct iovec
21962b15cb3dSCy Schubert #define IOV_PTR_FIELD iov_base
21972b15cb3dSCy Schubert #define IOV_LEN_FIELD iov_len
21982b15cb3dSCy Schubert #define IOV_LEN_TYPE size_t
21992b15cb3dSCy Schubert #else
22002b15cb3dSCy Schubert #define NUM_WRITE_IOVEC 16
22012b15cb3dSCy Schubert #define IOV_TYPE WSABUF
22022b15cb3dSCy Schubert #define IOV_PTR_FIELD buf
22032b15cb3dSCy Schubert #define IOV_LEN_FIELD len
22042b15cb3dSCy Schubert #define IOV_LEN_TYPE unsigned long
22052b15cb3dSCy Schubert #endif
22062b15cb3dSCy Schubert #endif
22072b15cb3dSCy Schubert #define NUM_READ_IOVEC 4
22082b15cb3dSCy Schubert
22092b15cb3dSCy Schubert #define EVBUFFER_MAX_READ 4096
22102b15cb3dSCy Schubert
22112b15cb3dSCy Schubert /** Helper function to figure out which space to use for reading data into
22122b15cb3dSCy Schubert an evbuffer. Internal use only.
22132b15cb3dSCy Schubert
22142b15cb3dSCy Schubert @param buf The buffer to read into
22152b15cb3dSCy Schubert @param howmuch How much we want to read.
22162b15cb3dSCy Schubert @param vecs An array of two or more iovecs or WSABUFs.
22172b15cb3dSCy Schubert @param n_vecs_avail The length of vecs
22182b15cb3dSCy Schubert @param chainp A pointer to a variable to hold the first chain we're
22192b15cb3dSCy Schubert reading into.
22202b15cb3dSCy Schubert @param exact Boolean: if true, we do not provide more than 'howmuch'
22212b15cb3dSCy Schubert space in the vectors, even if more space is available.
22222b15cb3dSCy Schubert @return The number of buffers we're using.
22232b15cb3dSCy Schubert */
22242b15cb3dSCy Schubert int
evbuffer_read_setup_vecs_(struct evbuffer * buf,ev_ssize_t howmuch,struct evbuffer_iovec * vecs,int n_vecs_avail,struct evbuffer_chain *** chainp,int exact)22252b15cb3dSCy Schubert evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
22262b15cb3dSCy Schubert struct evbuffer_iovec *vecs, int n_vecs_avail,
22272b15cb3dSCy Schubert struct evbuffer_chain ***chainp, int exact)
22282b15cb3dSCy Schubert {
22292b15cb3dSCy Schubert struct evbuffer_chain *chain;
22302b15cb3dSCy Schubert struct evbuffer_chain **firstchainp;
22312b15cb3dSCy Schubert size_t so_far;
22322b15cb3dSCy Schubert int i;
22332b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buf);
22342b15cb3dSCy Schubert
22352b15cb3dSCy Schubert if (howmuch < 0)
22362b15cb3dSCy Schubert return -1;
22372b15cb3dSCy Schubert
22382b15cb3dSCy Schubert so_far = 0;
22392b15cb3dSCy Schubert /* Let firstchain be the first chain with any space on it */
22402b15cb3dSCy Schubert firstchainp = buf->last_with_datap;
2241*a466cc55SCy Schubert EVUTIL_ASSERT(*firstchainp);
22422b15cb3dSCy Schubert if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
22432b15cb3dSCy Schubert firstchainp = &(*firstchainp)->next;
22442b15cb3dSCy Schubert }
22452b15cb3dSCy Schubert
22462b15cb3dSCy Schubert chain = *firstchainp;
2247*a466cc55SCy Schubert EVUTIL_ASSERT(chain);
22482b15cb3dSCy Schubert for (i = 0; i < n_vecs_avail && so_far < (size_t)howmuch; ++i) {
22492b15cb3dSCy Schubert size_t avail = (size_t) CHAIN_SPACE_LEN(chain);
22502b15cb3dSCy Schubert if (avail > (howmuch - so_far) && exact)
22512b15cb3dSCy Schubert avail = howmuch - so_far;
2252*a466cc55SCy Schubert vecs[i].iov_base = (void *)CHAIN_SPACE_PTR(chain);
22532b15cb3dSCy Schubert vecs[i].iov_len = avail;
22542b15cb3dSCy Schubert so_far += avail;
22552b15cb3dSCy Schubert chain = chain->next;
22562b15cb3dSCy Schubert }
22572b15cb3dSCy Schubert
22582b15cb3dSCy Schubert *chainp = firstchainp;
22592b15cb3dSCy Schubert return i;
22602b15cb3dSCy Schubert }
22612b15cb3dSCy Schubert
22622b15cb3dSCy Schubert static int
get_n_bytes_readable_on_socket(evutil_socket_t fd)22632b15cb3dSCy Schubert get_n_bytes_readable_on_socket(evutil_socket_t fd)
22642b15cb3dSCy Schubert {
22652b15cb3dSCy Schubert #if defined(FIONREAD) && defined(_WIN32)
22662b15cb3dSCy Schubert unsigned long lng = EVBUFFER_MAX_READ;
22672b15cb3dSCy Schubert if (ioctlsocket(fd, FIONREAD, &lng) < 0)
22682b15cb3dSCy Schubert return -1;
2269a25439b6SCy Schubert /* Can overflow, but mostly harmlessly. XXXX */
22702b15cb3dSCy Schubert return (int)lng;
22712b15cb3dSCy Schubert #elif defined(FIONREAD)
22722b15cb3dSCy Schubert int n = EVBUFFER_MAX_READ;
22732b15cb3dSCy Schubert if (ioctl(fd, FIONREAD, &n) < 0)
22742b15cb3dSCy Schubert return -1;
22752b15cb3dSCy Schubert return n;
22762b15cb3dSCy Schubert #else
22772b15cb3dSCy Schubert return EVBUFFER_MAX_READ;
22782b15cb3dSCy Schubert #endif
22792b15cb3dSCy Schubert }
22802b15cb3dSCy Schubert
22812b15cb3dSCy Schubert /* TODO(niels): should this function return ev_ssize_t and take ev_ssize_t
22822b15cb3dSCy Schubert * as howmuch? */
22832b15cb3dSCy Schubert int
evbuffer_read(struct evbuffer * buf,evutil_socket_t fd,int howmuch)22842b15cb3dSCy Schubert evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
22852b15cb3dSCy Schubert {
22862b15cb3dSCy Schubert struct evbuffer_chain **chainp;
22872b15cb3dSCy Schubert int n;
22882b15cb3dSCy Schubert int result;
22892b15cb3dSCy Schubert
22902b15cb3dSCy Schubert #ifdef USE_IOVEC_IMPL
22912b15cb3dSCy Schubert int nvecs, i, remaining;
22922b15cb3dSCy Schubert #else
22932b15cb3dSCy Schubert struct evbuffer_chain *chain;
22942b15cb3dSCy Schubert unsigned char *p;
22952b15cb3dSCy Schubert #endif
22962b15cb3dSCy Schubert
22972b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
22982b15cb3dSCy Schubert
22992b15cb3dSCy Schubert if (buf->freeze_end) {
23002b15cb3dSCy Schubert result = -1;
23012b15cb3dSCy Schubert goto done;
23022b15cb3dSCy Schubert }
23032b15cb3dSCy Schubert
23042b15cb3dSCy Schubert n = get_n_bytes_readable_on_socket(fd);
23052b15cb3dSCy Schubert if (n <= 0 || n > EVBUFFER_MAX_READ)
23062b15cb3dSCy Schubert n = EVBUFFER_MAX_READ;
23072b15cb3dSCy Schubert if (howmuch < 0 || howmuch > n)
23082b15cb3dSCy Schubert howmuch = n;
23092b15cb3dSCy Schubert
23102b15cb3dSCy Schubert #ifdef USE_IOVEC_IMPL
23112b15cb3dSCy Schubert /* Since we can use iovecs, we're willing to use the last
23122b15cb3dSCy Schubert * NUM_READ_IOVEC chains. */
23132b15cb3dSCy Schubert if (evbuffer_expand_fast_(buf, howmuch, NUM_READ_IOVEC) == -1) {
23142b15cb3dSCy Schubert result = -1;
23152b15cb3dSCy Schubert goto done;
23162b15cb3dSCy Schubert } else {
23172b15cb3dSCy Schubert IOV_TYPE vecs[NUM_READ_IOVEC];
23182b15cb3dSCy Schubert #ifdef EVBUFFER_IOVEC_IS_NATIVE_
23192b15cb3dSCy Schubert nvecs = evbuffer_read_setup_vecs_(buf, howmuch, vecs,
23202b15cb3dSCy Schubert NUM_READ_IOVEC, &chainp, 1);
23212b15cb3dSCy Schubert #else
23222b15cb3dSCy Schubert /* We aren't using the native struct iovec. Therefore,
23232b15cb3dSCy Schubert we are on win32. */
23242b15cb3dSCy Schubert struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
23252b15cb3dSCy Schubert nvecs = evbuffer_read_setup_vecs_(buf, howmuch, ev_vecs, 2,
23262b15cb3dSCy Schubert &chainp, 1);
23272b15cb3dSCy Schubert
23282b15cb3dSCy Schubert for (i=0; i < nvecs; ++i)
23292b15cb3dSCy Schubert WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
23302b15cb3dSCy Schubert #endif
23312b15cb3dSCy Schubert
23322b15cb3dSCy Schubert #ifdef _WIN32
23332b15cb3dSCy Schubert {
23342b15cb3dSCy Schubert DWORD bytesRead;
23352b15cb3dSCy Schubert DWORD flags=0;
23362b15cb3dSCy Schubert if (WSARecv(fd, vecs, nvecs, &bytesRead, &flags, NULL, NULL)) {
23372b15cb3dSCy Schubert /* The read failed. It might be a close,
23382b15cb3dSCy Schubert * or it might be an error. */
23392b15cb3dSCy Schubert if (WSAGetLastError() == WSAECONNABORTED)
23402b15cb3dSCy Schubert n = 0;
23412b15cb3dSCy Schubert else
23422b15cb3dSCy Schubert n = -1;
23432b15cb3dSCy Schubert } else
23442b15cb3dSCy Schubert n = bytesRead;
23452b15cb3dSCy Schubert }
23462b15cb3dSCy Schubert #else
23472b15cb3dSCy Schubert n = readv(fd, vecs, nvecs);
23482b15cb3dSCy Schubert #endif
23492b15cb3dSCy Schubert }
23502b15cb3dSCy Schubert
23512b15cb3dSCy Schubert #else /*!USE_IOVEC_IMPL*/
23522b15cb3dSCy Schubert /* If we don't have FIONREAD, we might waste some space here */
23532b15cb3dSCy Schubert /* XXX we _will_ waste some space here if there is any space left
23542b15cb3dSCy Schubert * over on buf->last. */
23552b15cb3dSCy Schubert if ((chain = evbuffer_expand_singlechain(buf, howmuch)) == NULL) {
23562b15cb3dSCy Schubert result = -1;
23572b15cb3dSCy Schubert goto done;
23582b15cb3dSCy Schubert }
23592b15cb3dSCy Schubert
23602b15cb3dSCy Schubert /* We can append new data at this point */
23612b15cb3dSCy Schubert p = chain->buffer + chain->misalign + chain->off;
23622b15cb3dSCy Schubert
23632b15cb3dSCy Schubert #ifndef _WIN32
23642b15cb3dSCy Schubert n = read(fd, p, howmuch);
23652b15cb3dSCy Schubert #else
23662b15cb3dSCy Schubert n = recv(fd, p, howmuch, 0);
23672b15cb3dSCy Schubert #endif
23682b15cb3dSCy Schubert #endif /* USE_IOVEC_IMPL */
23692b15cb3dSCy Schubert
23702b15cb3dSCy Schubert if (n == -1) {
23712b15cb3dSCy Schubert result = -1;
23722b15cb3dSCy Schubert goto done;
23732b15cb3dSCy Schubert }
23742b15cb3dSCy Schubert if (n == 0) {
23752b15cb3dSCy Schubert result = 0;
23762b15cb3dSCy Schubert goto done;
23772b15cb3dSCy Schubert }
23782b15cb3dSCy Schubert
23792b15cb3dSCy Schubert #ifdef USE_IOVEC_IMPL
23802b15cb3dSCy Schubert remaining = n;
23812b15cb3dSCy Schubert for (i=0; i < nvecs; ++i) {
2382a25439b6SCy Schubert /* can't overflow, since only mutable chains have
2383a25439b6SCy Schubert * huge misaligns. */
2384a25439b6SCy Schubert size_t space = (size_t) CHAIN_SPACE_LEN(*chainp);
2385a25439b6SCy Schubert /* XXXX This is a kludge that can waste space in perverse
2386a25439b6SCy Schubert * situations. */
2387a25439b6SCy Schubert if (space > EVBUFFER_CHAIN_MAX)
2388a25439b6SCy Schubert space = EVBUFFER_CHAIN_MAX;
2389a25439b6SCy Schubert if ((ev_ssize_t)space < remaining) {
23902b15cb3dSCy Schubert (*chainp)->off += space;
23912b15cb3dSCy Schubert remaining -= (int)space;
23922b15cb3dSCy Schubert } else {
23932b15cb3dSCy Schubert (*chainp)->off += remaining;
23942b15cb3dSCy Schubert buf->last_with_datap = chainp;
23952b15cb3dSCy Schubert break;
23962b15cb3dSCy Schubert }
23972b15cb3dSCy Schubert chainp = &(*chainp)->next;
23982b15cb3dSCy Schubert }
23992b15cb3dSCy Schubert #else
24002b15cb3dSCy Schubert chain->off += n;
24012b15cb3dSCy Schubert advance_last_with_data(buf);
24022b15cb3dSCy Schubert #endif
24032b15cb3dSCy Schubert buf->total_len += n;
24042b15cb3dSCy Schubert buf->n_add_for_cb += n;
24052b15cb3dSCy Schubert
24062b15cb3dSCy Schubert /* Tell someone about changes in this buffer */
24072b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
24082b15cb3dSCy Schubert result = n;
24092b15cb3dSCy Schubert done:
24102b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
24112b15cb3dSCy Schubert return result;
24122b15cb3dSCy Schubert }
24132b15cb3dSCy Schubert
24142b15cb3dSCy Schubert #ifdef USE_IOVEC_IMPL
24152b15cb3dSCy Schubert static inline int
evbuffer_write_iovec(struct evbuffer * buffer,evutil_socket_t fd,ev_ssize_t howmuch)24162b15cb3dSCy Schubert evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
24172b15cb3dSCy Schubert ev_ssize_t howmuch)
24182b15cb3dSCy Schubert {
24192b15cb3dSCy Schubert IOV_TYPE iov[NUM_WRITE_IOVEC];
24202b15cb3dSCy Schubert struct evbuffer_chain *chain = buffer->first;
24212b15cb3dSCy Schubert int n, i = 0;
24222b15cb3dSCy Schubert
24232b15cb3dSCy Schubert if (howmuch < 0)
24242b15cb3dSCy Schubert return -1;
24252b15cb3dSCy Schubert
24262b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buffer);
24272b15cb3dSCy Schubert /* XXX make this top out at some maximal data length? if the
24282b15cb3dSCy Schubert * buffer has (say) 1MB in it, split over 128 chains, there's
24292b15cb3dSCy Schubert * no way it all gets written in one go. */
24302b15cb3dSCy Schubert while (chain != NULL && i < NUM_WRITE_IOVEC && howmuch) {
24312b15cb3dSCy Schubert #ifdef USE_SENDFILE
24322b15cb3dSCy Schubert /* we cannot write the file info via writev */
24332b15cb3dSCy Schubert if (chain->flags & EVBUFFER_SENDFILE)
24342b15cb3dSCy Schubert break;
24352b15cb3dSCy Schubert #endif
24362b15cb3dSCy Schubert iov[i].IOV_PTR_FIELD = (void *) (chain->buffer + chain->misalign);
24372b15cb3dSCy Schubert if ((size_t)howmuch >= chain->off) {
24382b15cb3dSCy Schubert /* XXXcould be problematic when windows supports mmap*/
24392b15cb3dSCy Schubert iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)chain->off;
24402b15cb3dSCy Schubert howmuch -= chain->off;
24412b15cb3dSCy Schubert } else {
24422b15cb3dSCy Schubert /* XXXcould be problematic when windows supports mmap*/
24432b15cb3dSCy Schubert iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)howmuch;
24442b15cb3dSCy Schubert break;
24452b15cb3dSCy Schubert }
24462b15cb3dSCy Schubert chain = chain->next;
24472b15cb3dSCy Schubert }
24482b15cb3dSCy Schubert if (! i)
24492b15cb3dSCy Schubert return 0;
24502b15cb3dSCy Schubert
24512b15cb3dSCy Schubert #ifdef _WIN32
24522b15cb3dSCy Schubert {
24532b15cb3dSCy Schubert DWORD bytesSent;
24542b15cb3dSCy Schubert if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
24552b15cb3dSCy Schubert n = -1;
24562b15cb3dSCy Schubert else
24572b15cb3dSCy Schubert n = bytesSent;
24582b15cb3dSCy Schubert }
24592b15cb3dSCy Schubert #else
24602b15cb3dSCy Schubert n = writev(fd, iov, i);
24612b15cb3dSCy Schubert #endif
24622b15cb3dSCy Schubert return (n);
24632b15cb3dSCy Schubert }
24642b15cb3dSCy Schubert #endif
24652b15cb3dSCy Schubert
24662b15cb3dSCy Schubert #ifdef USE_SENDFILE
24672b15cb3dSCy Schubert static inline int
evbuffer_write_sendfile(struct evbuffer * buffer,evutil_socket_t dest_fd,ev_ssize_t howmuch)24682b15cb3dSCy Schubert evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
24692b15cb3dSCy Schubert ev_ssize_t howmuch)
24702b15cb3dSCy Schubert {
24712b15cb3dSCy Schubert struct evbuffer_chain *chain = buffer->first;
24722b15cb3dSCy Schubert struct evbuffer_chain_file_segment *info =
24732b15cb3dSCy Schubert EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment,
24742b15cb3dSCy Schubert chain);
24752b15cb3dSCy Schubert const int source_fd = info->segment->fd;
24762b15cb3dSCy Schubert #if defined(SENDFILE_IS_MACOSX) || defined(SENDFILE_IS_FREEBSD)
24772b15cb3dSCy Schubert int res;
24782b15cb3dSCy Schubert ev_off_t len = chain->off;
24792b15cb3dSCy Schubert #elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
24802b15cb3dSCy Schubert ev_ssize_t res;
2481*a466cc55SCy Schubert off_t offset = chain->misalign;
24822b15cb3dSCy Schubert #endif
24832b15cb3dSCy Schubert
24842b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buffer);
24852b15cb3dSCy Schubert
24862b15cb3dSCy Schubert #if defined(SENDFILE_IS_MACOSX)
24872b15cb3dSCy Schubert res = sendfile(source_fd, dest_fd, chain->misalign, &len, NULL, 0);
24882b15cb3dSCy Schubert if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
24892b15cb3dSCy Schubert return (-1);
24902b15cb3dSCy Schubert
24912b15cb3dSCy Schubert return (len);
24922b15cb3dSCy Schubert #elif defined(SENDFILE_IS_FREEBSD)
24932b15cb3dSCy Schubert res = sendfile(source_fd, dest_fd, chain->misalign, chain->off, NULL, &len, 0);
24942b15cb3dSCy Schubert if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
24952b15cb3dSCy Schubert return (-1);
24962b15cb3dSCy Schubert
24972b15cb3dSCy Schubert return (len);
24982b15cb3dSCy Schubert #elif defined(SENDFILE_IS_LINUX)
24992b15cb3dSCy Schubert /* TODO(niels): implement splice */
25002b15cb3dSCy Schubert res = sendfile(dest_fd, source_fd, &offset, chain->off);
25012b15cb3dSCy Schubert if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
25022b15cb3dSCy Schubert /* if this is EAGAIN or EINTR return 0; otherwise, -1 */
25032b15cb3dSCy Schubert return (0);
25042b15cb3dSCy Schubert }
25052b15cb3dSCy Schubert return (res);
25062b15cb3dSCy Schubert #elif defined(SENDFILE_IS_SOLARIS)
25072b15cb3dSCy Schubert {
25082b15cb3dSCy Schubert const off_t offset_orig = offset;
25092b15cb3dSCy Schubert res = sendfile(dest_fd, source_fd, &offset, chain->off);
25102b15cb3dSCy Schubert if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
25112b15cb3dSCy Schubert if (offset - offset_orig)
25122b15cb3dSCy Schubert return offset - offset_orig;
25132b15cb3dSCy Schubert /* if this is EAGAIN or EINTR and no bytes were
25142b15cb3dSCy Schubert * written, return 0 */
25152b15cb3dSCy Schubert return (0);
25162b15cb3dSCy Schubert }
25172b15cb3dSCy Schubert return (res);
25182b15cb3dSCy Schubert }
25192b15cb3dSCy Schubert #endif
25202b15cb3dSCy Schubert }
25212b15cb3dSCy Schubert #endif
25222b15cb3dSCy Schubert
25232b15cb3dSCy Schubert int
evbuffer_write_atmost(struct evbuffer * buffer,evutil_socket_t fd,ev_ssize_t howmuch)25242b15cb3dSCy Schubert evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
25252b15cb3dSCy Schubert ev_ssize_t howmuch)
25262b15cb3dSCy Schubert {
25272b15cb3dSCy Schubert int n = -1;
25282b15cb3dSCy Schubert
25292b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
25302b15cb3dSCy Schubert
25312b15cb3dSCy Schubert if (buffer->freeze_start) {
25322b15cb3dSCy Schubert goto done;
25332b15cb3dSCy Schubert }
25342b15cb3dSCy Schubert
25352b15cb3dSCy Schubert if (howmuch < 0 || (size_t)howmuch > buffer->total_len)
25362b15cb3dSCy Schubert howmuch = buffer->total_len;
25372b15cb3dSCy Schubert
25382b15cb3dSCy Schubert if (howmuch > 0) {
25392b15cb3dSCy Schubert #ifdef USE_SENDFILE
25402b15cb3dSCy Schubert struct evbuffer_chain *chain = buffer->first;
25412b15cb3dSCy Schubert if (chain != NULL && (chain->flags & EVBUFFER_SENDFILE))
25422b15cb3dSCy Schubert n = evbuffer_write_sendfile(buffer, fd, howmuch);
25432b15cb3dSCy Schubert else {
25442b15cb3dSCy Schubert #endif
25452b15cb3dSCy Schubert #ifdef USE_IOVEC_IMPL
25462b15cb3dSCy Schubert n = evbuffer_write_iovec(buffer, fd, howmuch);
25472b15cb3dSCy Schubert #elif defined(_WIN32)
25482b15cb3dSCy Schubert /* XXX(nickm) Don't disable this code until we know if
25492b15cb3dSCy Schubert * the WSARecv code above works. */
25502b15cb3dSCy Schubert void *p = evbuffer_pullup(buffer, howmuch);
2551a25439b6SCy Schubert EVUTIL_ASSERT(p || !howmuch);
25522b15cb3dSCy Schubert n = send(fd, p, howmuch, 0);
25532b15cb3dSCy Schubert #else
25542b15cb3dSCy Schubert void *p = evbuffer_pullup(buffer, howmuch);
2555a25439b6SCy Schubert EVUTIL_ASSERT(p || !howmuch);
25562b15cb3dSCy Schubert n = write(fd, p, howmuch);
25572b15cb3dSCy Schubert #endif
25582b15cb3dSCy Schubert #ifdef USE_SENDFILE
25592b15cb3dSCy Schubert }
25602b15cb3dSCy Schubert #endif
25612b15cb3dSCy Schubert }
25622b15cb3dSCy Schubert
25632b15cb3dSCy Schubert if (n > 0)
25642b15cb3dSCy Schubert evbuffer_drain(buffer, n);
25652b15cb3dSCy Schubert
25662b15cb3dSCy Schubert done:
25672b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
25682b15cb3dSCy Schubert return (n);
25692b15cb3dSCy Schubert }
25702b15cb3dSCy Schubert
25712b15cb3dSCy Schubert int
evbuffer_write(struct evbuffer * buffer,evutil_socket_t fd)25722b15cb3dSCy Schubert evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd)
25732b15cb3dSCy Schubert {
25742b15cb3dSCy Schubert return evbuffer_write_atmost(buffer, fd, -1);
25752b15cb3dSCy Schubert }
25762b15cb3dSCy Schubert
25772b15cb3dSCy Schubert unsigned char *
evbuffer_find(struct evbuffer * buffer,const unsigned char * what,size_t len)25782b15cb3dSCy Schubert evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len)
25792b15cb3dSCy Schubert {
25802b15cb3dSCy Schubert unsigned char *search;
25812b15cb3dSCy Schubert struct evbuffer_ptr ptr;
25822b15cb3dSCy Schubert
25832b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
25842b15cb3dSCy Schubert
25852b15cb3dSCy Schubert ptr = evbuffer_search(buffer, (const char *)what, len, NULL);
25862b15cb3dSCy Schubert if (ptr.pos < 0) {
25872b15cb3dSCy Schubert search = NULL;
25882b15cb3dSCy Schubert } else {
25892b15cb3dSCy Schubert search = evbuffer_pullup(buffer, ptr.pos + len);
25902b15cb3dSCy Schubert if (search)
25912b15cb3dSCy Schubert search += ptr.pos;
25922b15cb3dSCy Schubert }
25932b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
25942b15cb3dSCy Schubert return search;
25952b15cb3dSCy Schubert }
25962b15cb3dSCy Schubert
25972b15cb3dSCy Schubert /* Subract <b>howfar</b> from the position of <b>pos</b> within
25982b15cb3dSCy Schubert * <b>buf</b>. Returns 0 on success, -1 on failure.
25992b15cb3dSCy Schubert *
26002b15cb3dSCy Schubert * This isn't exposed yet, because of potential inefficiency issues.
26012b15cb3dSCy Schubert * Maybe it should be. */
26022b15cb3dSCy Schubert static int
evbuffer_ptr_subtract(struct evbuffer * buf,struct evbuffer_ptr * pos,size_t howfar)26032b15cb3dSCy Schubert evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
26042b15cb3dSCy Schubert size_t howfar)
26052b15cb3dSCy Schubert {
2606a25439b6SCy Schubert if (pos->pos < 0)
2607a25439b6SCy Schubert return -1;
26082b15cb3dSCy Schubert if (howfar > (size_t)pos->pos)
26092b15cb3dSCy Schubert return -1;
26102b15cb3dSCy Schubert if (pos->internal_.chain && howfar <= pos->internal_.pos_in_chain) {
26112b15cb3dSCy Schubert pos->internal_.pos_in_chain -= howfar;
26122b15cb3dSCy Schubert pos->pos -= howfar;
26132b15cb3dSCy Schubert return 0;
26142b15cb3dSCy Schubert } else {
26152b15cb3dSCy Schubert const size_t newpos = pos->pos - howfar;
26162b15cb3dSCy Schubert /* Here's the inefficient part: it walks over the
26172b15cb3dSCy Schubert * chains until we hit newpos. */
26182b15cb3dSCy Schubert return evbuffer_ptr_set(buf, pos, newpos, EVBUFFER_PTR_SET);
26192b15cb3dSCy Schubert }
26202b15cb3dSCy Schubert }
26212b15cb3dSCy Schubert
26222b15cb3dSCy Schubert int
evbuffer_ptr_set(struct evbuffer * buf,struct evbuffer_ptr * pos,size_t position,enum evbuffer_ptr_how how)26232b15cb3dSCy Schubert evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
26242b15cb3dSCy Schubert size_t position, enum evbuffer_ptr_how how)
26252b15cb3dSCy Schubert {
26262b15cb3dSCy Schubert size_t left = position;
26272b15cb3dSCy Schubert struct evbuffer_chain *chain = NULL;
26282b15cb3dSCy Schubert int result = 0;
26292b15cb3dSCy Schubert
26302b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
26312b15cb3dSCy Schubert
26322b15cb3dSCy Schubert switch (how) {
26332b15cb3dSCy Schubert case EVBUFFER_PTR_SET:
26342b15cb3dSCy Schubert chain = buf->first;
26352b15cb3dSCy Schubert pos->pos = position;
26362b15cb3dSCy Schubert position = 0;
26372b15cb3dSCy Schubert break;
26382b15cb3dSCy Schubert case EVBUFFER_PTR_ADD:
26392b15cb3dSCy Schubert /* this avoids iterating over all previous chains if
26402b15cb3dSCy Schubert we just want to advance the position */
2641a25439b6SCy Schubert if (pos->pos < 0 || EV_SIZE_MAX - position < (size_t)pos->pos) {
2642a25439b6SCy Schubert EVBUFFER_UNLOCK(buf);
2643a25439b6SCy Schubert return -1;
2644a25439b6SCy Schubert }
26452b15cb3dSCy Schubert chain = pos->internal_.chain;
26462b15cb3dSCy Schubert pos->pos += position;
26472b15cb3dSCy Schubert position = pos->internal_.pos_in_chain;
26482b15cb3dSCy Schubert break;
26492b15cb3dSCy Schubert }
26502b15cb3dSCy Schubert
2651a25439b6SCy Schubert EVUTIL_ASSERT(EV_SIZE_MAX - left >= position);
26522b15cb3dSCy Schubert while (chain && position + left >= chain->off) {
26532b15cb3dSCy Schubert left -= chain->off - position;
26542b15cb3dSCy Schubert chain = chain->next;
26552b15cb3dSCy Schubert position = 0;
26562b15cb3dSCy Schubert }
26572b15cb3dSCy Schubert if (chain) {
26582b15cb3dSCy Schubert pos->internal_.chain = chain;
26592b15cb3dSCy Schubert pos->internal_.pos_in_chain = position + left;
26602b15cb3dSCy Schubert } else if (left == 0) {
26612b15cb3dSCy Schubert /* The first byte in the (nonexistent) chain after the last chain */
26622b15cb3dSCy Schubert pos->internal_.chain = NULL;
26632b15cb3dSCy Schubert pos->internal_.pos_in_chain = 0;
26642b15cb3dSCy Schubert } else {
26652b15cb3dSCy Schubert PTR_NOT_FOUND(pos);
26662b15cb3dSCy Schubert result = -1;
26672b15cb3dSCy Schubert }
26682b15cb3dSCy Schubert
26692b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
26702b15cb3dSCy Schubert
26712b15cb3dSCy Schubert return result;
26722b15cb3dSCy Schubert }
26732b15cb3dSCy Schubert
26742b15cb3dSCy Schubert /**
26752b15cb3dSCy Schubert Compare the bytes in buf at position pos to the len bytes in mem. Return
26762b15cb3dSCy Schubert less than 0, 0, or greater than 0 as memcmp.
26772b15cb3dSCy Schubert */
26782b15cb3dSCy Schubert static int
evbuffer_ptr_memcmp(const struct evbuffer * buf,const struct evbuffer_ptr * pos,const char * mem,size_t len)26792b15cb3dSCy Schubert evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
26802b15cb3dSCy Schubert const char *mem, size_t len)
26812b15cb3dSCy Schubert {
26822b15cb3dSCy Schubert struct evbuffer_chain *chain;
26832b15cb3dSCy Schubert size_t position;
26842b15cb3dSCy Schubert int r;
26852b15cb3dSCy Schubert
26862b15cb3dSCy Schubert ASSERT_EVBUFFER_LOCKED(buf);
26872b15cb3dSCy Schubert
2688a25439b6SCy Schubert if (pos->pos < 0 ||
2689a25439b6SCy Schubert EV_SIZE_MAX - len < (size_t)pos->pos ||
2690a25439b6SCy Schubert pos->pos + len > buf->total_len)
26912b15cb3dSCy Schubert return -1;
26922b15cb3dSCy Schubert
26932b15cb3dSCy Schubert chain = pos->internal_.chain;
26942b15cb3dSCy Schubert position = pos->internal_.pos_in_chain;
26952b15cb3dSCy Schubert while (len && chain) {
26962b15cb3dSCy Schubert size_t n_comparable;
26972b15cb3dSCy Schubert if (len + position > chain->off)
26982b15cb3dSCy Schubert n_comparable = chain->off - position;
26992b15cb3dSCy Schubert else
27002b15cb3dSCy Schubert n_comparable = len;
27012b15cb3dSCy Schubert r = memcmp(chain->buffer + chain->misalign + position, mem,
27022b15cb3dSCy Schubert n_comparable);
27032b15cb3dSCy Schubert if (r)
27042b15cb3dSCy Schubert return r;
27052b15cb3dSCy Schubert mem += n_comparable;
27062b15cb3dSCy Schubert len -= n_comparable;
27072b15cb3dSCy Schubert position = 0;
27082b15cb3dSCy Schubert chain = chain->next;
27092b15cb3dSCy Schubert }
27102b15cb3dSCy Schubert
27112b15cb3dSCy Schubert return 0;
27122b15cb3dSCy Schubert }
27132b15cb3dSCy Schubert
27142b15cb3dSCy Schubert struct evbuffer_ptr
evbuffer_search(struct evbuffer * buffer,const char * what,size_t len,const struct evbuffer_ptr * start)27152b15cb3dSCy Schubert evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start)
27162b15cb3dSCy Schubert {
27172b15cb3dSCy Schubert return evbuffer_search_range(buffer, what, len, start, NULL);
27182b15cb3dSCy Schubert }
27192b15cb3dSCy Schubert
27202b15cb3dSCy Schubert struct evbuffer_ptr
evbuffer_search_range(struct evbuffer * buffer,const char * what,size_t len,const struct evbuffer_ptr * start,const struct evbuffer_ptr * end)27212b15cb3dSCy Schubert evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end)
27222b15cb3dSCy Schubert {
27232b15cb3dSCy Schubert struct evbuffer_ptr pos;
27242b15cb3dSCy Schubert struct evbuffer_chain *chain, *last_chain = NULL;
27252b15cb3dSCy Schubert const unsigned char *p;
27262b15cb3dSCy Schubert char first;
27272b15cb3dSCy Schubert
27282b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
27292b15cb3dSCy Schubert
27302b15cb3dSCy Schubert if (start) {
27312b15cb3dSCy Schubert memcpy(&pos, start, sizeof(pos));
27322b15cb3dSCy Schubert chain = pos.internal_.chain;
27332b15cb3dSCy Schubert } else {
27342b15cb3dSCy Schubert pos.pos = 0;
27352b15cb3dSCy Schubert chain = pos.internal_.chain = buffer->first;
27362b15cb3dSCy Schubert pos.internal_.pos_in_chain = 0;
27372b15cb3dSCy Schubert }
27382b15cb3dSCy Schubert
27392b15cb3dSCy Schubert if (end)
27402b15cb3dSCy Schubert last_chain = end->internal_.chain;
27412b15cb3dSCy Schubert
27422b15cb3dSCy Schubert if (!len || len > EV_SSIZE_MAX)
27432b15cb3dSCy Schubert goto done;
27442b15cb3dSCy Schubert
27452b15cb3dSCy Schubert first = what[0];
27462b15cb3dSCy Schubert
27472b15cb3dSCy Schubert while (chain) {
27482b15cb3dSCy Schubert const unsigned char *start_at =
27492b15cb3dSCy Schubert chain->buffer + chain->misalign +
27502b15cb3dSCy Schubert pos.internal_.pos_in_chain;
27512b15cb3dSCy Schubert p = memchr(start_at, first,
27522b15cb3dSCy Schubert chain->off - pos.internal_.pos_in_chain);
27532b15cb3dSCy Schubert if (p) {
27542b15cb3dSCy Schubert pos.pos += p - start_at;
27552b15cb3dSCy Schubert pos.internal_.pos_in_chain += p - start_at;
27562b15cb3dSCy Schubert if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
27572b15cb3dSCy Schubert if (end && pos.pos + (ev_ssize_t)len > end->pos)
27582b15cb3dSCy Schubert goto not_found;
27592b15cb3dSCy Schubert else
27602b15cb3dSCy Schubert goto done;
27612b15cb3dSCy Schubert }
27622b15cb3dSCy Schubert ++pos.pos;
27632b15cb3dSCy Schubert ++pos.internal_.pos_in_chain;
27642b15cb3dSCy Schubert if (pos.internal_.pos_in_chain == chain->off) {
27652b15cb3dSCy Schubert chain = pos.internal_.chain = chain->next;
27662b15cb3dSCy Schubert pos.internal_.pos_in_chain = 0;
27672b15cb3dSCy Schubert }
27682b15cb3dSCy Schubert } else {
27692b15cb3dSCy Schubert if (chain == last_chain)
27702b15cb3dSCy Schubert goto not_found;
27712b15cb3dSCy Schubert pos.pos += chain->off - pos.internal_.pos_in_chain;
27722b15cb3dSCy Schubert chain = pos.internal_.chain = chain->next;
27732b15cb3dSCy Schubert pos.internal_.pos_in_chain = 0;
27742b15cb3dSCy Schubert }
27752b15cb3dSCy Schubert }
27762b15cb3dSCy Schubert
27772b15cb3dSCy Schubert not_found:
27782b15cb3dSCy Schubert PTR_NOT_FOUND(&pos);
27792b15cb3dSCy Schubert done:
27802b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
27812b15cb3dSCy Schubert return pos;
27822b15cb3dSCy Schubert }
27832b15cb3dSCy Schubert
27842b15cb3dSCy Schubert int
evbuffer_peek(struct evbuffer * buffer,ev_ssize_t len,struct evbuffer_ptr * start_at,struct evbuffer_iovec * vec,int n_vec)27852b15cb3dSCy Schubert evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
27862b15cb3dSCy Schubert struct evbuffer_ptr *start_at,
27872b15cb3dSCy Schubert struct evbuffer_iovec *vec, int n_vec)
27882b15cb3dSCy Schubert {
27892b15cb3dSCy Schubert struct evbuffer_chain *chain;
27902b15cb3dSCy Schubert int idx = 0;
27912b15cb3dSCy Schubert ev_ssize_t len_so_far = 0;
27922b15cb3dSCy Schubert
27932b15cb3dSCy Schubert /* Avoid locking in trivial edge cases */
27942b15cb3dSCy Schubert if (start_at && start_at->internal_.chain == NULL)
27952b15cb3dSCy Schubert return 0;
27962b15cb3dSCy Schubert
27972b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
27982b15cb3dSCy Schubert
27992b15cb3dSCy Schubert if (start_at) {
28002b15cb3dSCy Schubert chain = start_at->internal_.chain;
28012b15cb3dSCy Schubert len_so_far = chain->off
28022b15cb3dSCy Schubert - start_at->internal_.pos_in_chain;
28032b15cb3dSCy Schubert idx = 1;
28042b15cb3dSCy Schubert if (n_vec > 0) {
2805*a466cc55SCy Schubert vec[0].iov_base = (void *)(chain->buffer + chain->misalign
2806*a466cc55SCy Schubert + start_at->internal_.pos_in_chain);
28072b15cb3dSCy Schubert vec[0].iov_len = len_so_far;
28082b15cb3dSCy Schubert }
28092b15cb3dSCy Schubert chain = chain->next;
28102b15cb3dSCy Schubert } else {
28112b15cb3dSCy Schubert chain = buffer->first;
28122b15cb3dSCy Schubert }
28132b15cb3dSCy Schubert
28142b15cb3dSCy Schubert if (n_vec == 0 && len < 0) {
28152b15cb3dSCy Schubert /* If no vectors are provided and they asked for "everything",
28162b15cb3dSCy Schubert * pretend they asked for the actual available amount. */
2817a25439b6SCy Schubert len = buffer->total_len;
2818a25439b6SCy Schubert if (start_at) {
2819a25439b6SCy Schubert len -= start_at->pos;
2820a25439b6SCy Schubert }
28212b15cb3dSCy Schubert }
28222b15cb3dSCy Schubert
28232b15cb3dSCy Schubert while (chain) {
28242b15cb3dSCy Schubert if (len >= 0 && len_so_far >= len)
28252b15cb3dSCy Schubert break;
28262b15cb3dSCy Schubert if (idx<n_vec) {
2827*a466cc55SCy Schubert vec[idx].iov_base = (void *)(chain->buffer + chain->misalign);
28282b15cb3dSCy Schubert vec[idx].iov_len = chain->off;
28292b15cb3dSCy Schubert } else if (len<0) {
28302b15cb3dSCy Schubert break;
28312b15cb3dSCy Schubert }
28322b15cb3dSCy Schubert ++idx;
28332b15cb3dSCy Schubert len_so_far += chain->off;
28342b15cb3dSCy Schubert chain = chain->next;
28352b15cb3dSCy Schubert }
28362b15cb3dSCy Schubert
28372b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
28382b15cb3dSCy Schubert
28392b15cb3dSCy Schubert return idx;
28402b15cb3dSCy Schubert }
28412b15cb3dSCy Schubert
28422b15cb3dSCy Schubert
28432b15cb3dSCy Schubert int
evbuffer_add_vprintf(struct evbuffer * buf,const char * fmt,va_list ap)28442b15cb3dSCy Schubert evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
28452b15cb3dSCy Schubert {
28462b15cb3dSCy Schubert char *buffer;
28472b15cb3dSCy Schubert size_t space;
28482b15cb3dSCy Schubert int sz, result = -1;
28492b15cb3dSCy Schubert va_list aq;
28502b15cb3dSCy Schubert struct evbuffer_chain *chain;
28512b15cb3dSCy Schubert
28522b15cb3dSCy Schubert
28532b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
28542b15cb3dSCy Schubert
28552b15cb3dSCy Schubert if (buf->freeze_end) {
28562b15cb3dSCy Schubert goto done;
28572b15cb3dSCy Schubert }
28582b15cb3dSCy Schubert
28592b15cb3dSCy Schubert /* make sure that at least some space is available */
28602b15cb3dSCy Schubert if ((chain = evbuffer_expand_singlechain(buf, 64)) == NULL)
28612b15cb3dSCy Schubert goto done;
28622b15cb3dSCy Schubert
28632b15cb3dSCy Schubert for (;;) {
28642b15cb3dSCy Schubert #if 0
28652b15cb3dSCy Schubert size_t used = chain->misalign + chain->off;
28662b15cb3dSCy Schubert buffer = (char *)chain->buffer + chain->misalign + chain->off;
28672b15cb3dSCy Schubert EVUTIL_ASSERT(chain->buffer_len >= used);
28682b15cb3dSCy Schubert space = chain->buffer_len - used;
28692b15cb3dSCy Schubert #endif
28702b15cb3dSCy Schubert buffer = (char*) CHAIN_SPACE_PTR(chain);
28712b15cb3dSCy Schubert space = (size_t) CHAIN_SPACE_LEN(chain);
28722b15cb3dSCy Schubert
28732b15cb3dSCy Schubert #ifndef va_copy
28742b15cb3dSCy Schubert #define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
28752b15cb3dSCy Schubert #endif
28762b15cb3dSCy Schubert va_copy(aq, ap);
28772b15cb3dSCy Schubert
28782b15cb3dSCy Schubert sz = evutil_vsnprintf(buffer, space, fmt, aq);
28792b15cb3dSCy Schubert
28802b15cb3dSCy Schubert va_end(aq);
28812b15cb3dSCy Schubert
28822b15cb3dSCy Schubert if (sz < 0)
28832b15cb3dSCy Schubert goto done;
2884a25439b6SCy Schubert if (INT_MAX >= EVBUFFER_CHAIN_MAX &&
2885a25439b6SCy Schubert (size_t)sz >= EVBUFFER_CHAIN_MAX)
2886a25439b6SCy Schubert goto done;
28872b15cb3dSCy Schubert if ((size_t)sz < space) {
28882b15cb3dSCy Schubert chain->off += sz;
28892b15cb3dSCy Schubert buf->total_len += sz;
28902b15cb3dSCy Schubert buf->n_add_for_cb += sz;
28912b15cb3dSCy Schubert
28922b15cb3dSCy Schubert advance_last_with_data(buf);
28932b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
28942b15cb3dSCy Schubert result = sz;
28952b15cb3dSCy Schubert goto done;
28962b15cb3dSCy Schubert }
28972b15cb3dSCy Schubert if ((chain = evbuffer_expand_singlechain(buf, sz + 1)) == NULL)
28982b15cb3dSCy Schubert goto done;
28992b15cb3dSCy Schubert }
29002b15cb3dSCy Schubert /* NOTREACHED */
29012b15cb3dSCy Schubert
29022b15cb3dSCy Schubert done:
29032b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
29042b15cb3dSCy Schubert return result;
29052b15cb3dSCy Schubert }
29062b15cb3dSCy Schubert
29072b15cb3dSCy Schubert int
evbuffer_add_printf(struct evbuffer * buf,const char * fmt,...)29082b15cb3dSCy Schubert evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
29092b15cb3dSCy Schubert {
29102b15cb3dSCy Schubert int res = -1;
29112b15cb3dSCy Schubert va_list ap;
29122b15cb3dSCy Schubert
29132b15cb3dSCy Schubert va_start(ap, fmt);
29142b15cb3dSCy Schubert res = evbuffer_add_vprintf(buf, fmt, ap);
29152b15cb3dSCy Schubert va_end(ap);
29162b15cb3dSCy Schubert
29172b15cb3dSCy Schubert return (res);
29182b15cb3dSCy Schubert }
29192b15cb3dSCy Schubert
29202b15cb3dSCy Schubert int
evbuffer_add_reference(struct evbuffer * outbuf,const void * data,size_t datlen,evbuffer_ref_cleanup_cb cleanupfn,void * extra)29212b15cb3dSCy Schubert evbuffer_add_reference(struct evbuffer *outbuf,
29222b15cb3dSCy Schubert const void *data, size_t datlen,
29232b15cb3dSCy Schubert evbuffer_ref_cleanup_cb cleanupfn, void *extra)
29242b15cb3dSCy Schubert {
29252b15cb3dSCy Schubert struct evbuffer_chain *chain;
29262b15cb3dSCy Schubert struct evbuffer_chain_reference *info;
29272b15cb3dSCy Schubert int result = -1;
29282b15cb3dSCy Schubert
29292b15cb3dSCy Schubert chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_reference));
29302b15cb3dSCy Schubert if (!chain)
29312b15cb3dSCy Schubert return (-1);
29322b15cb3dSCy Schubert chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
2933*a466cc55SCy Schubert chain->buffer = (unsigned char *)data;
29342b15cb3dSCy Schubert chain->buffer_len = datlen;
29352b15cb3dSCy Schubert chain->off = datlen;
29362b15cb3dSCy Schubert
29372b15cb3dSCy Schubert info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_reference, chain);
29382b15cb3dSCy Schubert info->cleanupfn = cleanupfn;
29392b15cb3dSCy Schubert info->extra = extra;
29402b15cb3dSCy Schubert
29412b15cb3dSCy Schubert EVBUFFER_LOCK(outbuf);
29422b15cb3dSCy Schubert if (outbuf->freeze_end) {
29432b15cb3dSCy Schubert /* don't call chain_free; we do not want to actually invoke
29442b15cb3dSCy Schubert * the cleanup function */
29452b15cb3dSCy Schubert mm_free(chain);
29462b15cb3dSCy Schubert goto done;
29472b15cb3dSCy Schubert }
29482b15cb3dSCy Schubert evbuffer_chain_insert(outbuf, chain);
29492b15cb3dSCy Schubert outbuf->n_add_for_cb += datlen;
29502b15cb3dSCy Schubert
29512b15cb3dSCy Schubert evbuffer_invoke_callbacks_(outbuf);
29522b15cb3dSCy Schubert
29532b15cb3dSCy Schubert result = 0;
29542b15cb3dSCy Schubert done:
29552b15cb3dSCy Schubert EVBUFFER_UNLOCK(outbuf);
29562b15cb3dSCy Schubert
29572b15cb3dSCy Schubert return result;
29582b15cb3dSCy Schubert }
29592b15cb3dSCy Schubert
29602b15cb3dSCy Schubert /* TODO(niels): we may want to add to automagically convert to mmap, in
29612b15cb3dSCy Schubert * case evbuffer_remove() or evbuffer_pullup() are being used.
29622b15cb3dSCy Schubert */
29632b15cb3dSCy Schubert struct evbuffer_file_segment *
evbuffer_file_segment_new(int fd,ev_off_t offset,ev_off_t length,unsigned flags)29642b15cb3dSCy Schubert evbuffer_file_segment_new(
29652b15cb3dSCy Schubert int fd, ev_off_t offset, ev_off_t length, unsigned flags)
29662b15cb3dSCy Schubert {
29672b15cb3dSCy Schubert struct evbuffer_file_segment *seg =
29682b15cb3dSCy Schubert mm_calloc(sizeof(struct evbuffer_file_segment), 1);
29692b15cb3dSCy Schubert if (!seg)
29702b15cb3dSCy Schubert return NULL;
29712b15cb3dSCy Schubert seg->refcnt = 1;
29722b15cb3dSCy Schubert seg->fd = fd;
29732b15cb3dSCy Schubert seg->flags = flags;
29742b15cb3dSCy Schubert seg->file_offset = offset;
29752b15cb3dSCy Schubert seg->cleanup_cb = NULL;
29762b15cb3dSCy Schubert seg->cleanup_cb_arg = NULL;
29772b15cb3dSCy Schubert #ifdef _WIN32
29782b15cb3dSCy Schubert #ifndef lseek
29792b15cb3dSCy Schubert #define lseek _lseeki64
29802b15cb3dSCy Schubert #endif
29812b15cb3dSCy Schubert #ifndef fstat
29822b15cb3dSCy Schubert #define fstat _fstat
29832b15cb3dSCy Schubert #endif
29842b15cb3dSCy Schubert #ifndef stat
29852b15cb3dSCy Schubert #define stat _stat
29862b15cb3dSCy Schubert #endif
29872b15cb3dSCy Schubert #endif
29882b15cb3dSCy Schubert if (length == -1) {
29892b15cb3dSCy Schubert struct stat st;
29902b15cb3dSCy Schubert if (fstat(fd, &st) < 0)
29912b15cb3dSCy Schubert goto err;
29922b15cb3dSCy Schubert length = st.st_size;
29932b15cb3dSCy Schubert }
29942b15cb3dSCy Schubert seg->length = length;
29952b15cb3dSCy Schubert
2996a25439b6SCy Schubert if (offset < 0 || length < 0 ||
2997a25439b6SCy Schubert ((ev_uint64_t)length > EVBUFFER_CHAIN_MAX) ||
2998a25439b6SCy Schubert (ev_uint64_t)offset > (ev_uint64_t)(EVBUFFER_CHAIN_MAX - length))
2999a25439b6SCy Schubert goto err;
3000a25439b6SCy Schubert
30012b15cb3dSCy Schubert #if defined(USE_SENDFILE)
30022b15cb3dSCy Schubert if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
30032b15cb3dSCy Schubert seg->can_sendfile = 1;
30042b15cb3dSCy Schubert goto done;
30052b15cb3dSCy Schubert }
30062b15cb3dSCy Schubert #endif
30072b15cb3dSCy Schubert
30082b15cb3dSCy Schubert if (evbuffer_file_segment_materialize(seg)<0)
30092b15cb3dSCy Schubert goto err;
30102b15cb3dSCy Schubert
30112b15cb3dSCy Schubert #if defined(USE_SENDFILE)
30122b15cb3dSCy Schubert done:
30132b15cb3dSCy Schubert #endif
30142b15cb3dSCy Schubert if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
30152b15cb3dSCy Schubert EVTHREAD_ALLOC_LOCK(seg->lock, 0);
30162b15cb3dSCy Schubert }
30172b15cb3dSCy Schubert return seg;
30182b15cb3dSCy Schubert err:
30192b15cb3dSCy Schubert mm_free(seg);
30202b15cb3dSCy Schubert return NULL;
30212b15cb3dSCy Schubert }
30222b15cb3dSCy Schubert
30232b15cb3dSCy Schubert #ifdef EVENT__HAVE_MMAP
30242b15cb3dSCy Schubert static long
get_page_size(void)30252b15cb3dSCy Schubert get_page_size(void)
30262b15cb3dSCy Schubert {
30272b15cb3dSCy Schubert #ifdef SC_PAGE_SIZE
30282b15cb3dSCy Schubert return sysconf(SC_PAGE_SIZE);
30292b15cb3dSCy Schubert #elif defined(_SC_PAGE_SIZE)
30302b15cb3dSCy Schubert return sysconf(_SC_PAGE_SIZE);
30312b15cb3dSCy Schubert #else
30322b15cb3dSCy Schubert return 1;
30332b15cb3dSCy Schubert #endif
30342b15cb3dSCy Schubert }
30352b15cb3dSCy Schubert #endif
30362b15cb3dSCy Schubert
30372b15cb3dSCy Schubert /* DOCDOC */
30382b15cb3dSCy Schubert /* Requires lock */
30392b15cb3dSCy Schubert static int
evbuffer_file_segment_materialize(struct evbuffer_file_segment * seg)30402b15cb3dSCy Schubert evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
30412b15cb3dSCy Schubert {
30422b15cb3dSCy Schubert const unsigned flags = seg->flags;
30432b15cb3dSCy Schubert const int fd = seg->fd;
30442b15cb3dSCy Schubert const ev_off_t length = seg->length;
30452b15cb3dSCy Schubert const ev_off_t offset = seg->file_offset;
30462b15cb3dSCy Schubert
30472b15cb3dSCy Schubert if (seg->contents)
30482b15cb3dSCy Schubert return 0; /* already materialized */
30492b15cb3dSCy Schubert
30502b15cb3dSCy Schubert #if defined(EVENT__HAVE_MMAP)
30512b15cb3dSCy Schubert if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
30522b15cb3dSCy Schubert off_t offset_rounded = 0, offset_leftover = 0;
30532b15cb3dSCy Schubert void *mapped;
30542b15cb3dSCy Schubert if (offset) {
30552b15cb3dSCy Schubert /* mmap implementations don't generally like us
30562b15cb3dSCy Schubert * to have an offset that isn't a round */
30572b15cb3dSCy Schubert long page_size = get_page_size();
30582b15cb3dSCy Schubert if (page_size == -1)
30592b15cb3dSCy Schubert goto err;
30602b15cb3dSCy Schubert offset_leftover = offset % page_size;
30612b15cb3dSCy Schubert offset_rounded = offset - offset_leftover;
30622b15cb3dSCy Schubert }
30632b15cb3dSCy Schubert mapped = mmap(NULL, length + offset_leftover,
30642b15cb3dSCy Schubert PROT_READ,
30652b15cb3dSCy Schubert #ifdef MAP_NOCACHE
30662b15cb3dSCy Schubert MAP_NOCACHE | /* ??? */
30672b15cb3dSCy Schubert #endif
30682b15cb3dSCy Schubert #ifdef MAP_FILE
30692b15cb3dSCy Schubert MAP_FILE |
30702b15cb3dSCy Schubert #endif
30712b15cb3dSCy Schubert MAP_PRIVATE,
30722b15cb3dSCy Schubert fd, offset_rounded);
30732b15cb3dSCy Schubert if (mapped == MAP_FAILED) {
30742b15cb3dSCy Schubert event_warn("%s: mmap(%d, %d, %zu) failed",
30752b15cb3dSCy Schubert __func__, fd, 0, (size_t)(offset + length));
30762b15cb3dSCy Schubert } else {
30772b15cb3dSCy Schubert seg->mapping = mapped;
30782b15cb3dSCy Schubert seg->contents = (char*)mapped+offset_leftover;
30792b15cb3dSCy Schubert seg->mmap_offset = 0;
30802b15cb3dSCy Schubert seg->is_mapping = 1;
30812b15cb3dSCy Schubert goto done;
30822b15cb3dSCy Schubert }
30832b15cb3dSCy Schubert }
30842b15cb3dSCy Schubert #endif
30852b15cb3dSCy Schubert #ifdef _WIN32
30862b15cb3dSCy Schubert if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
30872b15cb3dSCy Schubert intptr_t h = _get_osfhandle(fd);
30882b15cb3dSCy Schubert HANDLE m;
30892b15cb3dSCy Schubert ev_uint64_t total_size = length+offset;
30902b15cb3dSCy Schubert if ((HANDLE)h == INVALID_HANDLE_VALUE)
30912b15cb3dSCy Schubert goto err;
30922b15cb3dSCy Schubert m = CreateFileMapping((HANDLE)h, NULL, PAGE_READONLY,
30932b15cb3dSCy Schubert (total_size >> 32), total_size & 0xfffffffful,
30942b15cb3dSCy Schubert NULL);
30952b15cb3dSCy Schubert if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
30962b15cb3dSCy Schubert seg->mapping_handle = m;
30972b15cb3dSCy Schubert seg->mmap_offset = offset;
30982b15cb3dSCy Schubert seg->is_mapping = 1;
30992b15cb3dSCy Schubert goto done;
31002b15cb3dSCy Schubert }
31012b15cb3dSCy Schubert }
31022b15cb3dSCy Schubert #endif
31032b15cb3dSCy Schubert {
31042b15cb3dSCy Schubert ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos;
31052b15cb3dSCy Schubert ev_off_t read_so_far = 0;
31062b15cb3dSCy Schubert char *mem;
31072b15cb3dSCy Schubert int e;
31082b15cb3dSCy Schubert ev_ssize_t n = 0;
31092b15cb3dSCy Schubert if (!(mem = mm_malloc(length)))
31102b15cb3dSCy Schubert goto err;
31112b15cb3dSCy Schubert if (start_pos < 0) {
31122b15cb3dSCy Schubert mm_free(mem);
31132b15cb3dSCy Schubert goto err;
31142b15cb3dSCy Schubert }
31152b15cb3dSCy Schubert if (lseek(fd, offset, SEEK_SET) < 0) {
31162b15cb3dSCy Schubert mm_free(mem);
31172b15cb3dSCy Schubert goto err;
31182b15cb3dSCy Schubert }
31192b15cb3dSCy Schubert while (read_so_far < length) {
31202b15cb3dSCy Schubert n = read(fd, mem+read_so_far, length-read_so_far);
31212b15cb3dSCy Schubert if (n <= 0)
31222b15cb3dSCy Schubert break;
31232b15cb3dSCy Schubert read_so_far += n;
31242b15cb3dSCy Schubert }
31252b15cb3dSCy Schubert
31262b15cb3dSCy Schubert e = errno;
31272b15cb3dSCy Schubert pos = lseek(fd, start_pos, SEEK_SET);
31282b15cb3dSCy Schubert if (n < 0 || (n == 0 && length > read_so_far)) {
31292b15cb3dSCy Schubert mm_free(mem);
31302b15cb3dSCy Schubert errno = e;
31312b15cb3dSCy Schubert goto err;
31322b15cb3dSCy Schubert } else if (pos < 0) {
31332b15cb3dSCy Schubert mm_free(mem);
31342b15cb3dSCy Schubert goto err;
31352b15cb3dSCy Schubert }
31362b15cb3dSCy Schubert
31372b15cb3dSCy Schubert seg->contents = mem;
31382b15cb3dSCy Schubert }
31392b15cb3dSCy Schubert
31402b15cb3dSCy Schubert done:
31412b15cb3dSCy Schubert return 0;
31422b15cb3dSCy Schubert err:
31432b15cb3dSCy Schubert return -1;
31442b15cb3dSCy Schubert }
31452b15cb3dSCy Schubert
evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment * seg,evbuffer_file_segment_cleanup_cb cb,void * arg)31462b15cb3dSCy Schubert void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
31472b15cb3dSCy Schubert evbuffer_file_segment_cleanup_cb cb, void* arg)
31482b15cb3dSCy Schubert {
31492b15cb3dSCy Schubert EVUTIL_ASSERT(seg->refcnt > 0);
31502b15cb3dSCy Schubert seg->cleanup_cb = cb;
31512b15cb3dSCy Schubert seg->cleanup_cb_arg = arg;
31522b15cb3dSCy Schubert }
31532b15cb3dSCy Schubert
31542b15cb3dSCy Schubert void
evbuffer_file_segment_free(struct evbuffer_file_segment * seg)31552b15cb3dSCy Schubert evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
31562b15cb3dSCy Schubert {
31572b15cb3dSCy Schubert int refcnt;
31582b15cb3dSCy Schubert EVLOCK_LOCK(seg->lock, 0);
31592b15cb3dSCy Schubert refcnt = --seg->refcnt;
31602b15cb3dSCy Schubert EVLOCK_UNLOCK(seg->lock, 0);
31612b15cb3dSCy Schubert if (refcnt > 0)
31622b15cb3dSCy Schubert return;
31632b15cb3dSCy Schubert EVUTIL_ASSERT(refcnt == 0);
31642b15cb3dSCy Schubert
31652b15cb3dSCy Schubert if (seg->is_mapping) {
31662b15cb3dSCy Schubert #ifdef _WIN32
31672b15cb3dSCy Schubert CloseHandle(seg->mapping_handle);
31682b15cb3dSCy Schubert #elif defined (EVENT__HAVE_MMAP)
31692b15cb3dSCy Schubert off_t offset_leftover;
31702b15cb3dSCy Schubert offset_leftover = seg->file_offset % get_page_size();
31712b15cb3dSCy Schubert if (munmap(seg->mapping, seg->length + offset_leftover) == -1)
31722b15cb3dSCy Schubert event_warn("%s: munmap failed", __func__);
31732b15cb3dSCy Schubert #endif
31742b15cb3dSCy Schubert } else if (seg->contents) {
31752b15cb3dSCy Schubert mm_free(seg->contents);
31762b15cb3dSCy Schubert }
31772b15cb3dSCy Schubert
31782b15cb3dSCy Schubert if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
31792b15cb3dSCy Schubert close(seg->fd);
31802b15cb3dSCy Schubert }
31812b15cb3dSCy Schubert
31822b15cb3dSCy Schubert if (seg->cleanup_cb) {
31832b15cb3dSCy Schubert (*seg->cleanup_cb)((struct evbuffer_file_segment const*)seg,
31842b15cb3dSCy Schubert seg->flags, seg->cleanup_cb_arg);
31852b15cb3dSCy Schubert seg->cleanup_cb = NULL;
31862b15cb3dSCy Schubert seg->cleanup_cb_arg = NULL;
31872b15cb3dSCy Schubert }
31882b15cb3dSCy Schubert
31892b15cb3dSCy Schubert EVTHREAD_FREE_LOCK(seg->lock, 0);
31902b15cb3dSCy Schubert mm_free(seg);
31912b15cb3dSCy Schubert }
31922b15cb3dSCy Schubert
31932b15cb3dSCy Schubert int
evbuffer_add_file_segment(struct evbuffer * buf,struct evbuffer_file_segment * seg,ev_off_t offset,ev_off_t length)31942b15cb3dSCy Schubert evbuffer_add_file_segment(struct evbuffer *buf,
31952b15cb3dSCy Schubert struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length)
31962b15cb3dSCy Schubert {
31972b15cb3dSCy Schubert struct evbuffer_chain *chain;
31982b15cb3dSCy Schubert struct evbuffer_chain_file_segment *extra;
31992b15cb3dSCy Schubert int can_use_sendfile = 0;
32002b15cb3dSCy Schubert
32012b15cb3dSCy Schubert EVBUFFER_LOCK(buf);
32022b15cb3dSCy Schubert EVLOCK_LOCK(seg->lock, 0);
32032b15cb3dSCy Schubert if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
32042b15cb3dSCy Schubert can_use_sendfile = 1;
32052b15cb3dSCy Schubert } else {
32062b15cb3dSCy Schubert if (!seg->contents) {
32072b15cb3dSCy Schubert if (evbuffer_file_segment_materialize(seg)<0) {
32082b15cb3dSCy Schubert EVLOCK_UNLOCK(seg->lock, 0);
32092b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
32102b15cb3dSCy Schubert return -1;
32112b15cb3dSCy Schubert }
32122b15cb3dSCy Schubert }
32132b15cb3dSCy Schubert }
32142b15cb3dSCy Schubert EVLOCK_UNLOCK(seg->lock, 0);
32152b15cb3dSCy Schubert
32162b15cb3dSCy Schubert if (buf->freeze_end)
32172b15cb3dSCy Schubert goto err;
32182b15cb3dSCy Schubert
32192b15cb3dSCy Schubert if (length < 0) {
32202b15cb3dSCy Schubert if (offset > seg->length)
32212b15cb3dSCy Schubert goto err;
32222b15cb3dSCy Schubert length = seg->length - offset;
32232b15cb3dSCy Schubert }
32242b15cb3dSCy Schubert
32252b15cb3dSCy Schubert /* Can we actually add this? */
32262b15cb3dSCy Schubert if (offset+length > seg->length)
32272b15cb3dSCy Schubert goto err;
32282b15cb3dSCy Schubert
32292b15cb3dSCy Schubert chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment));
32302b15cb3dSCy Schubert if (!chain)
32312b15cb3dSCy Schubert goto err;
32322b15cb3dSCy Schubert extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
32332b15cb3dSCy Schubert
32342b15cb3dSCy Schubert chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
32352b15cb3dSCy Schubert if (can_use_sendfile && seg->can_sendfile) {
32362b15cb3dSCy Schubert chain->flags |= EVBUFFER_SENDFILE;
32372b15cb3dSCy Schubert chain->misalign = seg->file_offset + offset;
32382b15cb3dSCy Schubert chain->off = length;
32392b15cb3dSCy Schubert chain->buffer_len = chain->misalign + length;
32402b15cb3dSCy Schubert } else if (seg->is_mapping) {
32412b15cb3dSCy Schubert #ifdef _WIN32
32422b15cb3dSCy Schubert ev_uint64_t total_offset = seg->mmap_offset+offset;
32432b15cb3dSCy Schubert ev_uint64_t offset_rounded=0, offset_remaining=0;
32442b15cb3dSCy Schubert LPVOID data;
32452b15cb3dSCy Schubert if (total_offset) {
32462b15cb3dSCy Schubert SYSTEM_INFO si;
32472b15cb3dSCy Schubert memset(&si, 0, sizeof(si)); /* cargo cult */
32482b15cb3dSCy Schubert GetSystemInfo(&si);
32492b15cb3dSCy Schubert offset_remaining = total_offset % si.dwAllocationGranularity;
32502b15cb3dSCy Schubert offset_rounded = total_offset - offset_remaining;
32512b15cb3dSCy Schubert }
32522b15cb3dSCy Schubert data = MapViewOfFile(
32532b15cb3dSCy Schubert seg->mapping_handle,
32542b15cb3dSCy Schubert FILE_MAP_READ,
32552b15cb3dSCy Schubert offset_rounded >> 32,
32562b15cb3dSCy Schubert offset_rounded & 0xfffffffful,
32572b15cb3dSCy Schubert length + offset_remaining);
32582b15cb3dSCy Schubert if (data == NULL) {
32592b15cb3dSCy Schubert mm_free(chain);
32602b15cb3dSCy Schubert goto err;
32612b15cb3dSCy Schubert }
32622b15cb3dSCy Schubert chain->buffer = (unsigned char*) data;
32632b15cb3dSCy Schubert chain->buffer_len = length+offset_remaining;
32642b15cb3dSCy Schubert chain->misalign = offset_remaining;
32652b15cb3dSCy Schubert chain->off = length;
32662b15cb3dSCy Schubert #else
32672b15cb3dSCy Schubert chain->buffer = (unsigned char*)(seg->contents + offset);
32682b15cb3dSCy Schubert chain->buffer_len = length;
32692b15cb3dSCy Schubert chain->off = length;
32702b15cb3dSCy Schubert #endif
32712b15cb3dSCy Schubert } else {
32722b15cb3dSCy Schubert chain->buffer = (unsigned char*)(seg->contents + offset);
32732b15cb3dSCy Schubert chain->buffer_len = length;
32742b15cb3dSCy Schubert chain->off = length;
32752b15cb3dSCy Schubert }
32762b15cb3dSCy Schubert
3277*a466cc55SCy Schubert EVLOCK_LOCK(seg->lock, 0);
3278*a466cc55SCy Schubert ++seg->refcnt;
3279*a466cc55SCy Schubert EVLOCK_UNLOCK(seg->lock, 0);
32802b15cb3dSCy Schubert extra->segment = seg;
32812b15cb3dSCy Schubert buf->n_add_for_cb += length;
32822b15cb3dSCy Schubert evbuffer_chain_insert(buf, chain);
32832b15cb3dSCy Schubert
32842b15cb3dSCy Schubert evbuffer_invoke_callbacks_(buf);
32852b15cb3dSCy Schubert
32862b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
32872b15cb3dSCy Schubert
32882b15cb3dSCy Schubert return 0;
32892b15cb3dSCy Schubert err:
32902b15cb3dSCy Schubert EVBUFFER_UNLOCK(buf);
3291a25439b6SCy Schubert evbuffer_file_segment_free(seg); /* Lowers the refcount */
32922b15cb3dSCy Schubert return -1;
32932b15cb3dSCy Schubert }
32942b15cb3dSCy Schubert
32952b15cb3dSCy Schubert int
evbuffer_add_file(struct evbuffer * buf,int fd,ev_off_t offset,ev_off_t length)32962b15cb3dSCy Schubert evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length)
32972b15cb3dSCy Schubert {
32982b15cb3dSCy Schubert struct evbuffer_file_segment *seg;
32992b15cb3dSCy Schubert unsigned flags = EVBUF_FS_CLOSE_ON_FREE;
33002b15cb3dSCy Schubert int r;
33012b15cb3dSCy Schubert
33022b15cb3dSCy Schubert seg = evbuffer_file_segment_new(fd, offset, length, flags);
33032b15cb3dSCy Schubert if (!seg)
33042b15cb3dSCy Schubert return -1;
33052b15cb3dSCy Schubert r = evbuffer_add_file_segment(buf, seg, 0, length);
33062b15cb3dSCy Schubert if (r == 0)
33072b15cb3dSCy Schubert evbuffer_file_segment_free(seg);
33082b15cb3dSCy Schubert return r;
33092b15cb3dSCy Schubert }
33102b15cb3dSCy Schubert
3311*a466cc55SCy Schubert int
evbuffer_setcb(struct evbuffer * buffer,evbuffer_cb cb,void * cbarg)33122b15cb3dSCy Schubert evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
33132b15cb3dSCy Schubert {
33142b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
33152b15cb3dSCy Schubert
33162b15cb3dSCy Schubert if (!LIST_EMPTY(&buffer->callbacks))
33172b15cb3dSCy Schubert evbuffer_remove_all_callbacks(buffer);
33182b15cb3dSCy Schubert
33192b15cb3dSCy Schubert if (cb) {
33202b15cb3dSCy Schubert struct evbuffer_cb_entry *ent =
33212b15cb3dSCy Schubert evbuffer_add_cb(buffer, NULL, cbarg);
3322*a466cc55SCy Schubert if (!ent) {
3323*a466cc55SCy Schubert EVBUFFER_UNLOCK(buffer);
3324*a466cc55SCy Schubert return -1;
3325*a466cc55SCy Schubert }
33262b15cb3dSCy Schubert ent->cb.cb_obsolete = cb;
33272b15cb3dSCy Schubert ent->flags |= EVBUFFER_CB_OBSOLETE;
33282b15cb3dSCy Schubert }
33292b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
3330*a466cc55SCy Schubert return 0;
33312b15cb3dSCy Schubert }
33322b15cb3dSCy Schubert
33332b15cb3dSCy Schubert struct evbuffer_cb_entry *
evbuffer_add_cb(struct evbuffer * buffer,evbuffer_cb_func cb,void * cbarg)33342b15cb3dSCy Schubert evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
33352b15cb3dSCy Schubert {
33362b15cb3dSCy Schubert struct evbuffer_cb_entry *e;
33372b15cb3dSCy Schubert if (! (e = mm_calloc(1, sizeof(struct evbuffer_cb_entry))))
33382b15cb3dSCy Schubert return NULL;
33392b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
33402b15cb3dSCy Schubert e->cb.cb_func = cb;
33412b15cb3dSCy Schubert e->cbarg = cbarg;
33422b15cb3dSCy Schubert e->flags = EVBUFFER_CB_ENABLED;
33432b15cb3dSCy Schubert LIST_INSERT_HEAD(&buffer->callbacks, e, next);
33442b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
33452b15cb3dSCy Schubert return e;
33462b15cb3dSCy Schubert }
33472b15cb3dSCy Schubert
33482b15cb3dSCy Schubert int
evbuffer_remove_cb_entry(struct evbuffer * buffer,struct evbuffer_cb_entry * ent)33492b15cb3dSCy Schubert evbuffer_remove_cb_entry(struct evbuffer *buffer,
33502b15cb3dSCy Schubert struct evbuffer_cb_entry *ent)
33512b15cb3dSCy Schubert {
33522b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
33532b15cb3dSCy Schubert LIST_REMOVE(ent, next);
33542b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
33552b15cb3dSCy Schubert mm_free(ent);
33562b15cb3dSCy Schubert return 0;
33572b15cb3dSCy Schubert }
33582b15cb3dSCy Schubert
33592b15cb3dSCy Schubert int
evbuffer_remove_cb(struct evbuffer * buffer,evbuffer_cb_func cb,void * cbarg)33602b15cb3dSCy Schubert evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
33612b15cb3dSCy Schubert {
33622b15cb3dSCy Schubert struct evbuffer_cb_entry *cbent;
33632b15cb3dSCy Schubert int result = -1;
33642b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
33652b15cb3dSCy Schubert LIST_FOREACH(cbent, &buffer->callbacks, next) {
33662b15cb3dSCy Schubert if (cb == cbent->cb.cb_func && cbarg == cbent->cbarg) {
33672b15cb3dSCy Schubert result = evbuffer_remove_cb_entry(buffer, cbent);
33682b15cb3dSCy Schubert goto done;
33692b15cb3dSCy Schubert }
33702b15cb3dSCy Schubert }
33712b15cb3dSCy Schubert done:
33722b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
33732b15cb3dSCy Schubert return result;
33742b15cb3dSCy Schubert }
33752b15cb3dSCy Schubert
33762b15cb3dSCy Schubert int
evbuffer_cb_set_flags(struct evbuffer * buffer,struct evbuffer_cb_entry * cb,ev_uint32_t flags)33772b15cb3dSCy Schubert evbuffer_cb_set_flags(struct evbuffer *buffer,
33782b15cb3dSCy Schubert struct evbuffer_cb_entry *cb, ev_uint32_t flags)
33792b15cb3dSCy Schubert {
33802b15cb3dSCy Schubert /* the user isn't allowed to mess with these. */
33812b15cb3dSCy Schubert flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
33822b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
33832b15cb3dSCy Schubert cb->flags |= flags;
33842b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
33852b15cb3dSCy Schubert return 0;
33862b15cb3dSCy Schubert }
33872b15cb3dSCy Schubert
33882b15cb3dSCy Schubert int
evbuffer_cb_clear_flags(struct evbuffer * buffer,struct evbuffer_cb_entry * cb,ev_uint32_t flags)33892b15cb3dSCy Schubert evbuffer_cb_clear_flags(struct evbuffer *buffer,
33902b15cb3dSCy Schubert struct evbuffer_cb_entry *cb, ev_uint32_t flags)
33912b15cb3dSCy Schubert {
33922b15cb3dSCy Schubert /* the user isn't allowed to mess with these. */
33932b15cb3dSCy Schubert flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
33942b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
33952b15cb3dSCy Schubert cb->flags &= ~flags;
33962b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
33972b15cb3dSCy Schubert return 0;
33982b15cb3dSCy Schubert }
33992b15cb3dSCy Schubert
34002b15cb3dSCy Schubert int
evbuffer_freeze(struct evbuffer * buffer,int start)34012b15cb3dSCy Schubert evbuffer_freeze(struct evbuffer *buffer, int start)
34022b15cb3dSCy Schubert {
34032b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
34042b15cb3dSCy Schubert if (start)
34052b15cb3dSCy Schubert buffer->freeze_start = 1;
34062b15cb3dSCy Schubert else
34072b15cb3dSCy Schubert buffer->freeze_end = 1;
34082b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
34092b15cb3dSCy Schubert return 0;
34102b15cb3dSCy Schubert }
34112b15cb3dSCy Schubert
34122b15cb3dSCy Schubert int
evbuffer_unfreeze(struct evbuffer * buffer,int start)34132b15cb3dSCy Schubert evbuffer_unfreeze(struct evbuffer *buffer, int start)
34142b15cb3dSCy Schubert {
34152b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
34162b15cb3dSCy Schubert if (start)
34172b15cb3dSCy Schubert buffer->freeze_start = 0;
34182b15cb3dSCy Schubert else
34192b15cb3dSCy Schubert buffer->freeze_end = 0;
34202b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
34212b15cb3dSCy Schubert return 0;
34222b15cb3dSCy Schubert }
34232b15cb3dSCy Schubert
34242b15cb3dSCy Schubert #if 0
34252b15cb3dSCy Schubert void
34262b15cb3dSCy Schubert evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
34272b15cb3dSCy Schubert {
34282b15cb3dSCy Schubert if (!(cb->flags & EVBUFFER_CB_SUSPENDED)) {
34292b15cb3dSCy Schubert cb->size_before_suspend = evbuffer_get_length(buffer);
34302b15cb3dSCy Schubert cb->flags |= EVBUFFER_CB_SUSPENDED;
34312b15cb3dSCy Schubert }
34322b15cb3dSCy Schubert }
34332b15cb3dSCy Schubert
34342b15cb3dSCy Schubert void
34352b15cb3dSCy Schubert evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
34362b15cb3dSCy Schubert {
34372b15cb3dSCy Schubert if ((cb->flags & EVBUFFER_CB_SUSPENDED)) {
34382b15cb3dSCy Schubert unsigned call = (cb->flags & EVBUFFER_CB_CALL_ON_UNSUSPEND);
34392b15cb3dSCy Schubert size_t sz = cb->size_before_suspend;
34402b15cb3dSCy Schubert cb->flags &= ~(EVBUFFER_CB_SUSPENDED|
34412b15cb3dSCy Schubert EVBUFFER_CB_CALL_ON_UNSUSPEND);
34422b15cb3dSCy Schubert cb->size_before_suspend = 0;
34432b15cb3dSCy Schubert if (call && (cb->flags & EVBUFFER_CB_ENABLED)) {
34442b15cb3dSCy Schubert cb->cb(buffer, sz, evbuffer_get_length(buffer), cb->cbarg);
34452b15cb3dSCy Schubert }
34462b15cb3dSCy Schubert }
34472b15cb3dSCy Schubert }
34482b15cb3dSCy Schubert #endif
34492b15cb3dSCy Schubert
34502b15cb3dSCy Schubert int
evbuffer_get_callbacks_(struct evbuffer * buffer,struct event_callback ** cbs,int max_cbs)34512b15cb3dSCy Schubert evbuffer_get_callbacks_(struct evbuffer *buffer, struct event_callback **cbs,
34522b15cb3dSCy Schubert int max_cbs)
34532b15cb3dSCy Schubert {
34542b15cb3dSCy Schubert int r = 0;
34552b15cb3dSCy Schubert EVBUFFER_LOCK(buffer);
34562b15cb3dSCy Schubert if (buffer->deferred_cbs) {
34572b15cb3dSCy Schubert if (max_cbs < 1) {
34582b15cb3dSCy Schubert r = -1;
34592b15cb3dSCy Schubert goto done;
34602b15cb3dSCy Schubert }
34612b15cb3dSCy Schubert cbs[0] = &buffer->deferred;
34622b15cb3dSCy Schubert r = 1;
34632b15cb3dSCy Schubert }
34642b15cb3dSCy Schubert done:
34652b15cb3dSCy Schubert EVBUFFER_UNLOCK(buffer);
34662b15cb3dSCy Schubert return r;
34672b15cb3dSCy Schubert }
3468