Home | History | Annotate | Line # | Download | only in libevent
buffer.c revision 1.1.1.10
      1   1.1.1.9  christos /*	$NetBSD: buffer.c,v 1.1.1.10 2024/08/18 20:37:41 christos Exp $	*/
      2   1.1.1.9  christos 
      3       1.1  christos /*
      4       1.1  christos  * Copyright (c) 2002-2007 Niels Provos <provos (at) citi.umich.edu>
      5       1.1  christos  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
      6       1.1  christos  *
      7       1.1  christos  * Redistribution and use in source and binary forms, with or without
      8       1.1  christos  * modification, are permitted provided that the following conditions
      9       1.1  christos  * are met:
     10       1.1  christos  * 1. Redistributions of source code must retain the above copyright
     11       1.1  christos  *    notice, this list of conditions and the following disclaimer.
     12       1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     14       1.1  christos  *    documentation and/or other materials provided with the distribution.
     15       1.1  christos  * 3. The name of the author may not be used to endorse or promote products
     16       1.1  christos  *    derived from this software without specific prior written permission.
     17       1.1  christos  *
     18       1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19       1.1  christos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20       1.1  christos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21       1.1  christos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22       1.1  christos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23       1.1  christos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24       1.1  christos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25       1.1  christos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26       1.1  christos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27       1.1  christos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28       1.1  christos  */
     29       1.1  christos 
     30       1.1  christos #include "event2/event-config.h"
     31       1.1  christos #include "evconfig-private.h"
     32       1.1  christos 
     33       1.1  christos #ifdef _WIN32
     34       1.1  christos #include <winsock2.h>
     35       1.1  christos #include <windows.h>
     36       1.1  christos #include <io.h>
     37       1.1  christos #endif
     38       1.1  christos 
     39       1.1  christos #ifdef EVENT__HAVE_VASPRINTF
     40       1.1  christos /* If we have vasprintf, we need to define _GNU_SOURCE before we include
     41       1.1  christos  * stdio.h.  This comes from evconfig-private.h.
     42       1.1  christos  */
     43       1.1  christos #endif
     44       1.1  christos 
     45       1.1  christos #include <sys/types.h>
     46       1.1  christos 
     47       1.1  christos #ifdef EVENT__HAVE_SYS_TIME_H
     48       1.1  christos #include <sys/time.h>
     49       1.1  christos #endif
     50       1.1  christos 
     51       1.1  christos #ifdef EVENT__HAVE_SYS_SOCKET_H
     52       1.1  christos #include <sys/socket.h>
     53       1.1  christos #endif
     54       1.1  christos 
     55       1.1  christos #ifdef EVENT__HAVE_SYS_UIO_H
     56       1.1  christos #include <sys/uio.h>
     57       1.1  christos #endif
     58       1.1  christos 
     59       1.1  christos #ifdef EVENT__HAVE_SYS_IOCTL_H
     60       1.1  christos #include <sys/ioctl.h>
     61       1.1  christos #endif
     62       1.1  christos 
     63       1.1  christos #ifdef EVENT__HAVE_SYS_MMAN_H
     64       1.1  christos #include <sys/mman.h>
     65       1.1  christos #endif
     66       1.1  christos 
     67       1.1  christos #ifdef EVENT__HAVE_SYS_SENDFILE_H
     68       1.1  christos #include <sys/sendfile.h>
     69       1.1  christos #endif
     70       1.1  christos #ifdef EVENT__HAVE_SYS_STAT_H
     71       1.1  christos #include <sys/stat.h>
     72       1.1  christos #endif
     73       1.1  christos 
     74       1.1  christos 
     75       1.1  christos #include <errno.h>
     76       1.1  christos #include <stdio.h>
     77       1.1  christos #include <stdlib.h>
     78       1.1  christos #include <string.h>
     79       1.1  christos #ifdef EVENT__HAVE_STDARG_H
     80       1.1  christos #include <stdarg.h>
     81       1.1  christos #endif
     82       1.1  christos #ifdef EVENT__HAVE_UNISTD_H
     83       1.1  christos #include <unistd.h>
     84       1.1  christos #endif
     85       1.1  christos #include <limits.h>
     86       1.1  christos 
     87       1.1  christos #include "event2/event.h"
     88       1.1  christos #include "event2/buffer.h"
     89       1.1  christos #include "event2/buffer_compat.h"
     90       1.1  christos #include "event2/bufferevent.h"
     91       1.1  christos #include "event2/bufferevent_compat.h"
     92       1.1  christos #include "event2/bufferevent_struct.h"
     93       1.1  christos #include "event2/thread.h"
     94       1.1  christos #include "log-internal.h"
     95       1.1  christos #include "mm-internal.h"
     96       1.1  christos #include "util-internal.h"
     97       1.1  christos #include "evthread-internal.h"
     98       1.1  christos #include "evbuffer-internal.h"
     99       1.1  christos #include "bufferevent-internal.h"
    100  1.1.1.10  christos #include "event-internal.h"
    101       1.1  christos 
    102       1.1  christos /* some systems do not have MAP_FAILED */
    103       1.1  christos #ifndef MAP_FAILED
    104       1.1  christos #define MAP_FAILED	((void *)-1)
    105       1.1  christos #endif
    106       1.1  christos 
    107       1.1  christos /* send file support */
    108       1.1  christos #if defined(EVENT__HAVE_SYS_SENDFILE_H) && defined(EVENT__HAVE_SENDFILE) && defined(__linux__)
    109       1.1  christos #define USE_SENDFILE		1
    110       1.1  christos #define SENDFILE_IS_LINUX	1
    111       1.1  christos #elif defined(EVENT__HAVE_SENDFILE) && defined(__FreeBSD__)
    112       1.1  christos #define USE_SENDFILE		1
    113       1.1  christos #define SENDFILE_IS_FREEBSD	1
    114       1.1  christos #elif defined(EVENT__HAVE_SENDFILE) && defined(__APPLE__)
    115       1.1  christos #define USE_SENDFILE		1
    116       1.1  christos #define SENDFILE_IS_MACOSX	1
    117       1.1  christos #elif defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
    118       1.1  christos #define USE_SENDFILE		1
    119       1.1  christos #define SENDFILE_IS_SOLARIS	1
    120       1.1  christos #endif
    121       1.1  christos 
    122       1.1  christos /* Mask of user-selectable callback flags. */
    123       1.1  christos #define EVBUFFER_CB_USER_FLAGS	    0xffff
    124       1.1  christos /* Mask of all internal-use-only flags. */
    125       1.1  christos #define EVBUFFER_CB_INTERNAL_FLAGS  0xffff0000
    126       1.1  christos 
    127       1.1  christos /* Flag set if the callback is using the cb_obsolete function pointer  */
    128       1.1  christos #define EVBUFFER_CB_OBSOLETE	       0x00040000
    129       1.1  christos 
    130       1.1  christos /* evbuffer_chain support */
    131       1.1  christos #define CHAIN_SPACE_PTR(ch) ((ch)->buffer + (ch)->misalign + (ch)->off)
    132       1.1  christos #define CHAIN_SPACE_LEN(ch) ((ch)->flags & EVBUFFER_IMMUTABLE ? \
    133       1.1  christos 	    0 : (ch)->buffer_len - ((ch)->misalign + (ch)->off))
    134       1.1  christos 
    135       1.1  christos #define CHAIN_PINNED(ch)  (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
    136       1.1  christos #define CHAIN_PINNED_R(ch)  (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
    137       1.1  christos 
    138       1.1  christos /* evbuffer_ptr support */
    139       1.1  christos #define PTR_NOT_FOUND(ptr) do {			\
    140       1.1  christos 	(ptr)->pos = -1;					\
    141       1.1  christos 	(ptr)->internal_.chain = NULL;		\
    142       1.1  christos 	(ptr)->internal_.pos_in_chain = 0;	\
    143       1.1  christos } while (0)
    144       1.1  christos 
    145       1.1  christos static void evbuffer_chain_align(struct evbuffer_chain *chain);
    146       1.1  christos static int evbuffer_chain_should_realign(struct evbuffer_chain *chain,
    147       1.1  christos     size_t datalen);
    148       1.1  christos static void evbuffer_deferred_callback(struct event_callback *cb, void *arg);
    149       1.1  christos static int evbuffer_ptr_memcmp(const struct evbuffer *buf,
    150       1.1  christos     const struct evbuffer_ptr *pos, const char *mem, size_t len);
    151       1.1  christos static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
    152       1.1  christos     size_t datlen);
    153       1.1  christos static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
    154       1.1  christos     size_t howfar);
    155       1.1  christos static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
    156       1.1  christos static inline void evbuffer_chain_incref(struct evbuffer_chain *chain);
    157       1.1  christos 
    158       1.1  christos static struct evbuffer_chain *
    159       1.1  christos evbuffer_chain_new(size_t size)
    160       1.1  christos {
    161       1.1  christos 	struct evbuffer_chain *chain;
    162       1.1  christos 	size_t to_alloc;
    163       1.1  christos 
    164   1.1.1.3  christos 	if (size > EVBUFFER_CHAIN_MAX - EVBUFFER_CHAIN_SIZE)
    165   1.1.1.3  christos 		return (NULL);
    166   1.1.1.3  christos 
    167       1.1  christos 	size += EVBUFFER_CHAIN_SIZE;
    168       1.1  christos 
    169       1.1  christos 	/* get the next largest memory that can hold the buffer */
    170   1.1.1.3  christos 	if (size < EVBUFFER_CHAIN_MAX / 2) {
    171   1.1.1.3  christos 		to_alloc = MIN_BUFFER_SIZE;
    172   1.1.1.3  christos 		while (to_alloc < size) {
    173   1.1.1.3  christos 			to_alloc <<= 1;
    174   1.1.1.3  christos 		}
    175   1.1.1.3  christos 	} else {
    176   1.1.1.3  christos 		to_alloc = size;
    177   1.1.1.3  christos 	}
    178       1.1  christos 
    179       1.1  christos 	/* we get everything in one chunk */
    180       1.1  christos 	if ((chain = mm_malloc(to_alloc)) == NULL)
    181       1.1  christos 		return (NULL);
    182       1.1  christos 
    183       1.1  christos 	memset(chain, 0, EVBUFFER_CHAIN_SIZE);
    184       1.1  christos 
    185       1.1  christos 	chain->buffer_len = to_alloc - EVBUFFER_CHAIN_SIZE;
    186       1.1  christos 
    187       1.1  christos 	/* this way we can manipulate the buffer to different addresses,
    188       1.1  christos 	 * which is required for mmap for example.
    189       1.1  christos 	 */
    190  1.1.1.10  christos 	chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);
    191       1.1  christos 
    192       1.1  christos 	chain->refcnt = 1;
    193       1.1  christos 
    194       1.1  christos 	return (chain);
    195       1.1  christos }
    196       1.1  christos 
    197       1.1  christos static inline void
    198       1.1  christos evbuffer_chain_free(struct evbuffer_chain *chain)
    199       1.1  christos {
    200       1.1  christos 	EVUTIL_ASSERT(chain->refcnt > 0);
    201       1.1  christos 	if (--chain->refcnt > 0) {
    202       1.1  christos 		/* chain is still referenced by other chains */
    203       1.1  christos 		return;
    204       1.1  christos 	}
    205       1.1  christos 
    206       1.1  christos 	if (CHAIN_PINNED(chain)) {
    207       1.1  christos 		/* will get freed once no longer dangling */
    208       1.1  christos 		chain->refcnt++;
    209       1.1  christos 		chain->flags |= EVBUFFER_DANGLING;
    210       1.1  christos 		return;
    211       1.1  christos 	}
    212       1.1  christos 
    213       1.1  christos 	/* safe to release chain, it's either a referencing
    214       1.1  christos 	 * chain or all references to it have been freed */
    215       1.1  christos 	if (chain->flags & EVBUFFER_REFERENCE) {
    216       1.1  christos 		struct evbuffer_chain_reference *info =
    217       1.1  christos 		    EVBUFFER_CHAIN_EXTRA(
    218       1.1  christos 			    struct evbuffer_chain_reference,
    219       1.1  christos 			    chain);
    220       1.1  christos 		if (info->cleanupfn)
    221       1.1  christos 			(*info->cleanupfn)(chain->buffer,
    222       1.1  christos 			    chain->buffer_len,
    223       1.1  christos 			    info->extra);
    224       1.1  christos 	}
    225       1.1  christos 	if (chain->flags & EVBUFFER_FILESEGMENT) {
    226       1.1  christos 		struct evbuffer_chain_file_segment *info =
    227       1.1  christos 		    EVBUFFER_CHAIN_EXTRA(
    228       1.1  christos 			    struct evbuffer_chain_file_segment,
    229       1.1  christos 			    chain);
    230       1.1  christos 		if (info->segment) {
    231       1.1  christos #ifdef _WIN32
    232       1.1  christos 			if (info->segment->is_mapping)
    233       1.1  christos 				UnmapViewOfFile(chain->buffer);
    234       1.1  christos #endif
    235       1.1  christos 			evbuffer_file_segment_free(info->segment);
    236       1.1  christos 		}
    237       1.1  christos 	}
    238       1.1  christos 	if (chain->flags & EVBUFFER_MULTICAST) {
    239       1.1  christos 		struct evbuffer_multicast_parent *info =
    240       1.1  christos 		    EVBUFFER_CHAIN_EXTRA(
    241       1.1  christos 			    struct evbuffer_multicast_parent,
    242       1.1  christos 			    chain);
    243       1.1  christos 		/* referencing chain is being freed, decrease
    244       1.1  christos 		 * refcounts of source chain and associated
    245       1.1  christos 		 * evbuffer (which get freed once both reach
    246       1.1  christos 		 * zero) */
    247       1.1  christos 		EVUTIL_ASSERT(info->source != NULL);
    248       1.1  christos 		EVUTIL_ASSERT(info->parent != NULL);
    249       1.1  christos 		EVBUFFER_LOCK(info->source);
    250       1.1  christos 		evbuffer_chain_free(info->parent);
    251       1.1  christos 		evbuffer_decref_and_unlock_(info->source);
    252       1.1  christos 	}
    253       1.1  christos 
    254       1.1  christos 	mm_free(chain);
    255       1.1  christos }
    256       1.1  christos 
    257       1.1  christos static void
    258       1.1  christos evbuffer_free_all_chains(struct evbuffer_chain *chain)
    259       1.1  christos {
    260       1.1  christos 	struct evbuffer_chain *next;
    261       1.1  christos 	for (; chain; chain = next) {
    262       1.1  christos 		next = chain->next;
    263       1.1  christos 		evbuffer_chain_free(chain);
    264       1.1  christos 	}
    265       1.1  christos }
    266       1.1  christos 
    267       1.1  christos #ifndef NDEBUG
    268       1.1  christos static int
    269       1.1  christos evbuffer_chains_all_empty(struct evbuffer_chain *chain)
    270       1.1  christos {
    271       1.1  christos 	for (; chain; chain = chain->next) {
    272       1.1  christos 		if (chain->off)
    273       1.1  christos 			return 0;
    274       1.1  christos 	}
    275       1.1  christos 	return 1;
    276       1.1  christos }
    277       1.1  christos #else
    278       1.1  christos /* The definition is needed for EVUTIL_ASSERT, which uses sizeof to avoid
    279       1.1  christos "unused variable" warnings. */
    280       1.1  christos static inline int evbuffer_chains_all_empty(struct evbuffer_chain *chain) {
    281       1.1  christos 	return 1;
    282       1.1  christos }
    283       1.1  christos #endif
    284       1.1  christos 
    285       1.1  christos /* Free all trailing chains in 'buf' that are neither pinned nor empty, prior
    286       1.1  christos  * to replacing them all with a new chain.  Return a pointer to the place
    287       1.1  christos  * where the new chain will go.
    288       1.1  christos  *
    289       1.1  christos  * Internal; requires lock.  The caller must fix up buf->last and buf->first
    290       1.1  christos  * as needed; they might have been freed.
    291       1.1  christos  */
    292       1.1  christos static struct evbuffer_chain **
    293       1.1  christos evbuffer_free_trailing_empty_chains(struct evbuffer *buf)
    294       1.1  christos {
    295       1.1  christos 	struct evbuffer_chain **ch = buf->last_with_datap;
    296       1.1  christos 	/* Find the first victim chain.  It might be *last_with_datap */
    297       1.1  christos 	while ((*ch) && ((*ch)->off != 0 || CHAIN_PINNED(*ch)))
    298       1.1  christos 		ch = &(*ch)->next;
    299       1.1  christos 	if (*ch) {
    300       1.1  christos 		EVUTIL_ASSERT(evbuffer_chains_all_empty(*ch));
    301       1.1  christos 		evbuffer_free_all_chains(*ch);
    302       1.1  christos 		*ch = NULL;
    303       1.1  christos 	}
    304       1.1  christos 	return ch;
    305       1.1  christos }
    306       1.1  christos 
    307       1.1  christos /* Add a single chain 'chain' to the end of 'buf', freeing trailing empty
    308       1.1  christos  * chains as necessary.  Requires lock.  Does not schedule callbacks.
    309       1.1  christos  */
    310       1.1  christos static void
    311       1.1  christos evbuffer_chain_insert(struct evbuffer *buf,
    312       1.1  christos     struct evbuffer_chain *chain)
    313       1.1  christos {
    314       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buf);
    315       1.1  christos 	if (*buf->last_with_datap == NULL) {
    316       1.1  christos 		/* There are no chains data on the buffer at all. */
    317       1.1  christos 		EVUTIL_ASSERT(buf->last_with_datap == &buf->first);
    318       1.1  christos 		EVUTIL_ASSERT(buf->first == NULL);
    319       1.1  christos 		buf->first = buf->last = chain;
    320       1.1  christos 	} else {
    321       1.1  christos 		struct evbuffer_chain **chp;
    322       1.1  christos 		chp = evbuffer_free_trailing_empty_chains(buf);
    323       1.1  christos 		*chp = chain;
    324       1.1  christos 		if (chain->off)
    325       1.1  christos 			buf->last_with_datap = chp;
    326       1.1  christos 		buf->last = chain;
    327       1.1  christos 	}
    328       1.1  christos 	buf->total_len += chain->off;
    329       1.1  christos }
    330       1.1  christos 
    331       1.1  christos static inline struct evbuffer_chain *
    332       1.1  christos evbuffer_chain_insert_new(struct evbuffer *buf, size_t datlen)
    333       1.1  christos {
    334       1.1  christos 	struct evbuffer_chain *chain;
    335       1.1  christos 	if ((chain = evbuffer_chain_new(datlen)) == NULL)
    336       1.1  christos 		return NULL;
    337       1.1  christos 	evbuffer_chain_insert(buf, chain);
    338       1.1  christos 	return chain;
    339       1.1  christos }
    340       1.1  christos 
    341       1.1  christos void
    342       1.1  christos evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag)
    343       1.1  christos {
    344       1.1  christos 	EVUTIL_ASSERT((chain->flags & flag) == 0);
    345       1.1  christos 	chain->flags |= flag;
    346       1.1  christos }
    347       1.1  christos 
    348       1.1  christos void
    349       1.1  christos evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag)
    350       1.1  christos {
    351       1.1  christos 	EVUTIL_ASSERT((chain->flags & flag) != 0);
    352       1.1  christos 	chain->flags &= ~flag;
    353       1.1  christos 	if (chain->flags & EVBUFFER_DANGLING)
    354       1.1  christos 		evbuffer_chain_free(chain);
    355       1.1  christos }
    356       1.1  christos 
    357       1.1  christos static inline void
    358       1.1  christos evbuffer_chain_incref(struct evbuffer_chain *chain)
    359       1.1  christos {
    360       1.1  christos     ++chain->refcnt;
    361       1.1  christos }
    362       1.1  christos 
    363       1.1  christos struct evbuffer *
    364       1.1  christos evbuffer_new(void)
    365       1.1  christos {
    366       1.1  christos 	struct evbuffer *buffer;
    367       1.1  christos 
    368       1.1  christos 	buffer = mm_calloc(1, sizeof(struct evbuffer));
    369       1.1  christos 	if (buffer == NULL)
    370       1.1  christos 		return (NULL);
    371       1.1  christos 
    372       1.1  christos 	LIST_INIT(&buffer->callbacks);
    373       1.1  christos 	buffer->refcnt = 1;
    374       1.1  christos 	buffer->last_with_datap = &buffer->first;
    375       1.1  christos 
    376       1.1  christos 	return (buffer);
    377       1.1  christos }
    378       1.1  christos 
    379       1.1  christos int
    380       1.1  christos evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags)
    381       1.1  christos {
    382       1.1  christos 	EVBUFFER_LOCK(buf);
    383       1.1  christos 	buf->flags |= (ev_uint32_t)flags;
    384       1.1  christos 	EVBUFFER_UNLOCK(buf);
    385       1.1  christos 	return 0;
    386       1.1  christos }
    387       1.1  christos 
    388       1.1  christos int
    389       1.1  christos evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags)
    390       1.1  christos {
    391       1.1  christos 	EVBUFFER_LOCK(buf);
    392       1.1  christos 	buf->flags &= ~(ev_uint32_t)flags;
    393       1.1  christos 	EVBUFFER_UNLOCK(buf);
    394       1.1  christos 	return 0;
    395       1.1  christos }
    396       1.1  christos 
    397       1.1  christos void
    398       1.1  christos evbuffer_incref_(struct evbuffer *buf)
    399       1.1  christos {
    400       1.1  christos 	EVBUFFER_LOCK(buf);
    401       1.1  christos 	++buf->refcnt;
    402       1.1  christos 	EVBUFFER_UNLOCK(buf);
    403       1.1  christos }
    404       1.1  christos 
    405       1.1  christos void
    406       1.1  christos evbuffer_incref_and_lock_(struct evbuffer *buf)
    407       1.1  christos {
    408       1.1  christos 	EVBUFFER_LOCK(buf);
    409       1.1  christos 	++buf->refcnt;
    410       1.1  christos }
    411       1.1  christos 
    412       1.1  christos int
    413       1.1  christos evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base)
    414       1.1  christos {
    415       1.1  christos 	EVBUFFER_LOCK(buffer);
    416       1.1  christos 	buffer->cb_queue = base;
    417       1.1  christos 	buffer->deferred_cbs = 1;
    418       1.1  christos 	event_deferred_cb_init_(&buffer->deferred,
    419       1.1  christos 	    event_base_get_npriorities(base) / 2,
    420       1.1  christos 	    evbuffer_deferred_callback, buffer);
    421       1.1  christos 	EVBUFFER_UNLOCK(buffer);
    422       1.1  christos 	return 0;
    423       1.1  christos }
    424       1.1  christos 
    425       1.1  christos int
    426       1.1  christos evbuffer_enable_locking(struct evbuffer *buf, void *lock)
    427       1.1  christos {
    428       1.1  christos #ifdef EVENT__DISABLE_THREAD_SUPPORT
    429       1.1  christos 	return -1;
    430       1.1  christos #else
    431       1.1  christos 	if (buf->lock)
    432       1.1  christos 		return -1;
    433       1.1  christos 
    434       1.1  christos 	if (!lock) {
    435       1.1  christos 		EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
    436       1.1  christos 		if (!lock)
    437       1.1  christos 			return -1;
    438       1.1  christos 		buf->lock = lock;
    439       1.1  christos 		buf->own_lock = 1;
    440       1.1  christos 	} else {
    441       1.1  christos 		buf->lock = lock;
    442       1.1  christos 		buf->own_lock = 0;
    443       1.1  christos 	}
    444       1.1  christos 
    445       1.1  christos 	return 0;
    446       1.1  christos #endif
    447       1.1  christos }
    448       1.1  christos 
    449       1.1  christos void
    450       1.1  christos evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev)
    451       1.1  christos {
    452       1.1  christos 	EVBUFFER_LOCK(buf);
    453       1.1  christos 	buf->parent = bev;
    454       1.1  christos 	EVBUFFER_UNLOCK(buf);
    455       1.1  christos }
    456       1.1  christos 
    457       1.1  christos static void
    458       1.1  christos evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
    459       1.1  christos {
    460       1.1  christos 	struct evbuffer_cb_entry *cbent, *next;
    461       1.1  christos 	struct evbuffer_cb_info info;
    462       1.1  christos 	size_t new_size;
    463       1.1  christos 	ev_uint32_t mask, masked_val;
    464       1.1  christos 	int clear = 1;
    465       1.1  christos 
    466       1.1  christos 	if (running_deferred) {
    467       1.1  christos 		mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
    468       1.1  christos 		masked_val = EVBUFFER_CB_ENABLED;
    469       1.1  christos 	} else if (buffer->deferred_cbs) {
    470       1.1  christos 		mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
    471       1.1  christos 		masked_val = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
    472       1.1  christos 		/* Don't zero-out n_add/n_del, since the deferred callbacks
    473       1.1  christos 		   will want to see them. */
    474       1.1  christos 		clear = 0;
    475       1.1  christos 	} else {
    476       1.1  christos 		mask = EVBUFFER_CB_ENABLED;
    477       1.1  christos 		masked_val = EVBUFFER_CB_ENABLED;
    478       1.1  christos 	}
    479       1.1  christos 
    480       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buffer);
    481       1.1  christos 
    482       1.1  christos 	if (LIST_EMPTY(&buffer->callbacks)) {
    483       1.1  christos 		buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
    484       1.1  christos 		return;
    485       1.1  christos 	}
    486       1.1  christos 	if (buffer->n_add_for_cb == 0 && buffer->n_del_for_cb == 0)
    487       1.1  christos 		return;
    488       1.1  christos 
    489       1.1  christos 	new_size = buffer->total_len;
    490       1.1  christos 	info.orig_size = new_size + buffer->n_del_for_cb - buffer->n_add_for_cb;
    491       1.1  christos 	info.n_added = buffer->n_add_for_cb;
    492       1.1  christos 	info.n_deleted = buffer->n_del_for_cb;
    493       1.1  christos 	if (clear) {
    494       1.1  christos 		buffer->n_add_for_cb = 0;
    495       1.1  christos 		buffer->n_del_for_cb = 0;
    496       1.1  christos 	}
    497       1.1  christos 	for (cbent = LIST_FIRST(&buffer->callbacks);
    498       1.1  christos 	     cbent != LIST_END(&buffer->callbacks);
    499       1.1  christos 	     cbent = next) {
    500       1.1  christos 		/* Get the 'next' pointer now in case this callback decides
    501       1.1  christos 		 * to remove itself or something. */
    502       1.1  christos 		next = LIST_NEXT(cbent, next);
    503       1.1  christos 
    504       1.1  christos 		if ((cbent->flags & mask) != masked_val)
    505       1.1  christos 			continue;
    506       1.1  christos 
    507       1.1  christos 		if ((cbent->flags & EVBUFFER_CB_OBSOLETE))
    508       1.1  christos 			cbent->cb.cb_obsolete(buffer,
    509       1.1  christos 			    info.orig_size, new_size, cbent->cbarg);
    510       1.1  christos 		else
    511       1.1  christos 			cbent->cb.cb_func(buffer, &info, cbent->cbarg);
    512       1.1  christos 	}
    513       1.1  christos }
    514       1.1  christos 
    515       1.1  christos void
    516       1.1  christos evbuffer_invoke_callbacks_(struct evbuffer *buffer)
    517       1.1  christos {
    518       1.1  christos 	if (LIST_EMPTY(&buffer->callbacks)) {
    519       1.1  christos 		buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
    520       1.1  christos 		return;
    521       1.1  christos 	}
    522       1.1  christos 
    523       1.1  christos 	if (buffer->deferred_cbs) {
    524       1.1  christos 		if (event_deferred_cb_schedule_(buffer->cb_queue, &buffer->deferred)) {
    525       1.1  christos 			evbuffer_incref_and_lock_(buffer);
    526       1.1  christos 			if (buffer->parent)
    527       1.1  christos 				bufferevent_incref_(buffer->parent);
    528  1.1.1.10  christos 			EVBUFFER_UNLOCK(buffer);
    529       1.1  christos 		}
    530       1.1  christos 	}
    531       1.1  christos 
    532       1.1  christos 	evbuffer_run_callbacks(buffer, 0);
    533       1.1  christos }
    534       1.1  christos 
    535       1.1  christos static void
    536       1.1  christos evbuffer_deferred_callback(struct event_callback *cb, void *arg)
    537       1.1  christos {
    538       1.1  christos 	struct bufferevent *parent = NULL;
    539       1.1  christos 	struct evbuffer *buffer = arg;
    540       1.1  christos 
    541       1.1  christos 	/* XXXX It would be better to run these callbacks without holding the
    542       1.1  christos 	 * lock */
    543       1.1  christos 	EVBUFFER_LOCK(buffer);
    544       1.1  christos 	parent = buffer->parent;
    545       1.1  christos 	evbuffer_run_callbacks(buffer, 1);
    546       1.1  christos 	evbuffer_decref_and_unlock_(buffer);
    547       1.1  christos 	if (parent)
    548       1.1  christos 		bufferevent_decref_(parent);
    549       1.1  christos }
    550       1.1  christos 
    551       1.1  christos static void
    552       1.1  christos evbuffer_remove_all_callbacks(struct evbuffer *buffer)
    553       1.1  christos {
    554       1.1  christos 	struct evbuffer_cb_entry *cbent;
    555       1.1  christos 
    556       1.1  christos 	while ((cbent = LIST_FIRST(&buffer->callbacks))) {
    557       1.1  christos 		LIST_REMOVE(cbent, next);
    558       1.1  christos 		mm_free(cbent);
    559       1.1  christos 	}
    560       1.1  christos }
    561       1.1  christos 
    562       1.1  christos void
    563       1.1  christos evbuffer_decref_and_unlock_(struct evbuffer *buffer)
    564       1.1  christos {
    565       1.1  christos 	struct evbuffer_chain *chain, *next;
    566       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buffer);
    567       1.1  christos 
    568       1.1  christos 	EVUTIL_ASSERT(buffer->refcnt > 0);
    569       1.1  christos 
    570       1.1  christos 	if (--buffer->refcnt > 0) {
    571       1.1  christos 		EVBUFFER_UNLOCK(buffer);
    572       1.1  christos 		return;
    573       1.1  christos 	}
    574       1.1  christos 
    575       1.1  christos 	for (chain = buffer->first; chain != NULL; chain = next) {
    576       1.1  christos 		next = chain->next;
    577       1.1  christos 		evbuffer_chain_free(chain);
    578       1.1  christos 	}
    579       1.1  christos 	evbuffer_remove_all_callbacks(buffer);
    580       1.1  christos 	if (buffer->deferred_cbs)
    581       1.1  christos 		event_deferred_cb_cancel_(buffer->cb_queue, &buffer->deferred);
    582       1.1  christos 
    583       1.1  christos 	EVBUFFER_UNLOCK(buffer);
    584       1.1  christos 	if (buffer->own_lock)
    585       1.1  christos 		EVTHREAD_FREE_LOCK(buffer->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
    586       1.1  christos 	mm_free(buffer);
    587       1.1  christos }
    588       1.1  christos 
    589       1.1  christos void
    590       1.1  christos evbuffer_free(struct evbuffer *buffer)
    591       1.1  christos {
    592       1.1  christos 	EVBUFFER_LOCK(buffer);
    593       1.1  christos 	evbuffer_decref_and_unlock_(buffer);
    594       1.1  christos }
    595       1.1  christos 
    596       1.1  christos void
    597       1.1  christos evbuffer_lock(struct evbuffer *buf)
    598       1.1  christos {
    599       1.1  christos 	EVBUFFER_LOCK(buf);
    600       1.1  christos }
    601       1.1  christos 
    602       1.1  christos void
    603       1.1  christos evbuffer_unlock(struct evbuffer *buf)
    604       1.1  christos {
    605       1.1  christos 	EVBUFFER_UNLOCK(buf);
    606       1.1  christos }
    607       1.1  christos 
    608       1.1  christos size_t
    609       1.1  christos evbuffer_get_length(const struct evbuffer *buffer)
    610       1.1  christos {
    611       1.1  christos 	size_t result;
    612       1.1  christos 
    613       1.1  christos 	EVBUFFER_LOCK(buffer);
    614       1.1  christos 
    615       1.1  christos 	result = (buffer->total_len);
    616       1.1  christos 
    617       1.1  christos 	EVBUFFER_UNLOCK(buffer);
    618       1.1  christos 
    619       1.1  christos 	return result;
    620       1.1  christos }
    621       1.1  christos 
    622       1.1  christos size_t
    623       1.1  christos evbuffer_get_contiguous_space(const struct evbuffer *buf)
    624       1.1  christos {
    625       1.1  christos 	struct evbuffer_chain *chain;
    626       1.1  christos 	size_t result;
    627       1.1  christos 
    628       1.1  christos 	EVBUFFER_LOCK(buf);
    629       1.1  christos 	chain = buf->first;
    630       1.1  christos 	result = (chain != NULL ? chain->off : 0);
    631       1.1  christos 	EVBUFFER_UNLOCK(buf);
    632       1.1  christos 
    633       1.1  christos 	return result;
    634       1.1  christos }
    635       1.1  christos 
    636       1.1  christos size_t
    637       1.1  christos evbuffer_add_iovec(struct evbuffer * buf, struct evbuffer_iovec * vec, int n_vec) {
    638       1.1  christos 	int n;
    639       1.1  christos 	size_t res;
    640       1.1  christos 	size_t to_alloc;
    641       1.1  christos 
    642       1.1  christos 	EVBUFFER_LOCK(buf);
    643       1.1  christos 
    644       1.1  christos 	res = to_alloc = 0;
    645       1.1  christos 
    646       1.1  christos 	for (n = 0; n < n_vec; n++) {
    647       1.1  christos 		to_alloc += vec[n].iov_len;
    648       1.1  christos 	}
    649       1.1  christos 
    650       1.1  christos 	if (evbuffer_expand_fast_(buf, to_alloc, 2) < 0) {
    651       1.1  christos 		goto done;
    652       1.1  christos 	}
    653       1.1  christos 
    654       1.1  christos 	for (n = 0; n < n_vec; n++) {
    655       1.1  christos 		/* XXX each 'add' call here does a bunch of setup that's
    656       1.1  christos 		 * obviated by evbuffer_expand_fast_, and some cleanup that we
    657       1.1  christos 		 * would like to do only once.  Instead we should just extract
    658       1.1  christos 		 * the part of the code that's needed. */
    659       1.1  christos 
    660       1.1  christos 		if (evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len) < 0) {
    661       1.1  christos 			goto done;
    662       1.1  christos 		}
    663       1.1  christos 
    664       1.1  christos 		res += vec[n].iov_len;
    665       1.1  christos 	}
    666       1.1  christos 
    667       1.1  christos done:
    668       1.1  christos     EVBUFFER_UNLOCK(buf);
    669       1.1  christos     return res;
    670       1.1  christos }
    671       1.1  christos 
    672       1.1  christos int
    673       1.1  christos evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
    674       1.1  christos     struct evbuffer_iovec *vec, int n_vecs)
    675       1.1  christos {
    676       1.1  christos 	struct evbuffer_chain *chain, **chainp;
    677       1.1  christos 	int n = -1;
    678       1.1  christos 
    679       1.1  christos 	EVBUFFER_LOCK(buf);
    680       1.1  christos 	if (buf->freeze_end)
    681       1.1  christos 		goto done;
    682       1.1  christos 	if (n_vecs < 1)
    683       1.1  christos 		goto done;
    684       1.1  christos 	if (n_vecs == 1) {
    685       1.1  christos 		if ((chain = evbuffer_expand_singlechain(buf, size)) == NULL)
    686       1.1  christos 			goto done;
    687       1.1  christos 
    688  1.1.1.10  christos 		vec[0].iov_base = (void *)CHAIN_SPACE_PTR(chain);
    689  1.1.1.10  christos 		vec[0].iov_len = (size_t)CHAIN_SPACE_LEN(chain);
    690       1.1  christos 		EVUTIL_ASSERT(size<0 || (size_t)vec[0].iov_len >= (size_t)size);
    691       1.1  christos 		n = 1;
    692       1.1  christos 	} else {
    693       1.1  christos 		if (evbuffer_expand_fast_(buf, size, n_vecs)<0)
    694       1.1  christos 			goto done;
    695       1.1  christos 		n = evbuffer_read_setup_vecs_(buf, size, vec, n_vecs,
    696       1.1  christos 				&chainp, 0);
    697       1.1  christos 	}
    698       1.1  christos 
    699       1.1  christos done:
    700       1.1  christos 	EVBUFFER_UNLOCK(buf);
    701       1.1  christos 	return n;
    702       1.1  christos 
    703       1.1  christos }
    704       1.1  christos 
    705       1.1  christos static int
    706       1.1  christos advance_last_with_data(struct evbuffer *buf)
    707       1.1  christos {
    708       1.1  christos 	int n = 0;
    709  1.1.1.10  christos 	struct evbuffer_chain **chainp = buf->last_with_datap;
    710  1.1.1.10  christos 
    711       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buf);
    712       1.1  christos 
    713  1.1.1.10  christos 	if (!*chainp)
    714       1.1  christos 		return 0;
    715       1.1  christos 
    716  1.1.1.10  christos 	while ((*chainp)->next) {
    717  1.1.1.10  christos 		chainp = &(*chainp)->next;
    718  1.1.1.10  christos 		if ((*chainp)->off)
    719  1.1.1.10  christos 			buf->last_with_datap = chainp;
    720       1.1  christos 		++n;
    721       1.1  christos 	}
    722       1.1  christos 	return n;
    723       1.1  christos }
    724       1.1  christos 
    725       1.1  christos int
    726       1.1  christos evbuffer_commit_space(struct evbuffer *buf,
    727       1.1  christos     struct evbuffer_iovec *vec, int n_vecs)
    728       1.1  christos {
    729       1.1  christos 	struct evbuffer_chain *chain, **firstchainp, **chainp;
    730       1.1  christos 	int result = -1;
    731       1.1  christos 	size_t added = 0;
    732       1.1  christos 	int i;
    733       1.1  christos 
    734       1.1  christos 	EVBUFFER_LOCK(buf);
    735       1.1  christos 
    736       1.1  christos 	if (buf->freeze_end)
    737       1.1  christos 		goto done;
    738       1.1  christos 	if (n_vecs == 0) {
    739       1.1  christos 		result = 0;
    740       1.1  christos 		goto done;
    741       1.1  christos 	} else if (n_vecs == 1 &&
    742  1.1.1.10  christos 	    (buf->last && vec[0].iov_base == (void *)CHAIN_SPACE_PTR(buf->last))) {
    743       1.1  christos 		/* The user only got or used one chain; it might not
    744       1.1  christos 		 * be the first one with space in it. */
    745       1.1  christos 		if ((size_t)vec[0].iov_len > (size_t)CHAIN_SPACE_LEN(buf->last))
    746       1.1  christos 			goto done;
    747       1.1  christos 		buf->last->off += vec[0].iov_len;
    748       1.1  christos 		added = vec[0].iov_len;
    749       1.1  christos 		if (added)
    750       1.1  christos 			advance_last_with_data(buf);
    751       1.1  christos 		goto okay;
    752       1.1  christos 	}
    753       1.1  christos 
    754       1.1  christos 	/* Advance 'firstchain' to the first chain with space in it. */
    755       1.1  christos 	firstchainp = buf->last_with_datap;
    756       1.1  christos 	if (!*firstchainp)
    757       1.1  christos 		goto done;
    758       1.1  christos 	if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
    759       1.1  christos 		firstchainp = &(*firstchainp)->next;
    760       1.1  christos 	}
    761       1.1  christos 
    762       1.1  christos 	chain = *firstchainp;
    763       1.1  christos 	/* pass 1: make sure that the pointers and lengths of vecs[] are in
    764       1.1  christos 	 * bounds before we try to commit anything. */
    765       1.1  christos 	for (i=0; i<n_vecs; ++i) {
    766       1.1  christos 		if (!chain)
    767       1.1  christos 			goto done;
    768  1.1.1.10  christos 		if (vec[i].iov_base != (void *)CHAIN_SPACE_PTR(chain) ||
    769       1.1  christos 		    (size_t)vec[i].iov_len > CHAIN_SPACE_LEN(chain))
    770       1.1  christos 			goto done;
    771       1.1  christos 		chain = chain->next;
    772       1.1  christos 	}
    773       1.1  christos 	/* pass 2: actually adjust all the chains. */
    774       1.1  christos 	chainp = firstchainp;
    775       1.1  christos 	for (i=0; i<n_vecs; ++i) {
    776       1.1  christos 		(*chainp)->off += vec[i].iov_len;
    777       1.1  christos 		added += vec[i].iov_len;
    778       1.1  christos 		if (vec[i].iov_len) {
    779       1.1  christos 			buf->last_with_datap = chainp;
    780       1.1  christos 		}
    781       1.1  christos 		chainp = &(*chainp)->next;
    782       1.1  christos 	}
    783       1.1  christos 
    784       1.1  christos okay:
    785       1.1  christos 	buf->total_len += added;
    786       1.1  christos 	buf->n_add_for_cb += added;
    787       1.1  christos 	result = 0;
    788       1.1  christos 	evbuffer_invoke_callbacks_(buf);
    789       1.1  christos 
    790       1.1  christos done:
    791       1.1  christos 	EVBUFFER_UNLOCK(buf);
    792       1.1  christos 	return result;
    793       1.1  christos }
    794       1.1  christos 
    795       1.1  christos static inline int
    796       1.1  christos HAS_PINNED_R(struct evbuffer *buf)
    797       1.1  christos {
    798       1.1  christos 	return (buf->last && CHAIN_PINNED_R(buf->last));
    799       1.1  christos }
    800       1.1  christos 
    801       1.1  christos static inline void
    802       1.1  christos ZERO_CHAIN(struct evbuffer *dst)
    803       1.1  christos {
    804       1.1  christos 	ASSERT_EVBUFFER_LOCKED(dst);
    805       1.1  christos 	dst->first = NULL;
    806       1.1  christos 	dst->last = NULL;
    807       1.1  christos 	dst->last_with_datap = &(dst)->first;
    808       1.1  christos 	dst->total_len = 0;
    809       1.1  christos }
    810       1.1  christos 
    811       1.1  christos /* Prepares the contents of src to be moved to another buffer by removing
    812       1.1  christos  * read-pinned chains. The first pinned chain is saved in first, and the
    813       1.1  christos  * last in last. If src has no read-pinned chains, first and last are set
    814       1.1  christos  * to NULL. */
    815       1.1  christos static int
    816       1.1  christos PRESERVE_PINNED(struct evbuffer *src, struct evbuffer_chain **first,
    817       1.1  christos 		struct evbuffer_chain **last)
    818       1.1  christos {
    819       1.1  christos 	struct evbuffer_chain *chain, **pinned;
    820       1.1  christos 
    821       1.1  christos 	ASSERT_EVBUFFER_LOCKED(src);
    822       1.1  christos 
    823       1.1  christos 	if (!HAS_PINNED_R(src)) {
    824       1.1  christos 		*first = *last = NULL;
    825       1.1  christos 		return 0;
    826       1.1  christos 	}
    827       1.1  christos 
    828       1.1  christos 	pinned = src->last_with_datap;
    829       1.1  christos 	if (!CHAIN_PINNED_R(*pinned))
    830       1.1  christos 		pinned = &(*pinned)->next;
    831       1.1  christos 	EVUTIL_ASSERT(CHAIN_PINNED_R(*pinned));
    832       1.1  christos 	chain = *first = *pinned;
    833       1.1  christos 	*last = src->last;
    834       1.1  christos 
    835       1.1  christos 	/* If there's data in the first pinned chain, we need to allocate
    836       1.1  christos 	 * a new chain and copy the data over. */
    837       1.1  christos 	if (chain->off) {
    838       1.1  christos 		struct evbuffer_chain *tmp;
    839       1.1  christos 
    840       1.1  christos 		EVUTIL_ASSERT(pinned == src->last_with_datap);
    841       1.1  christos 		tmp = evbuffer_chain_new(chain->off);
    842       1.1  christos 		if (!tmp)
    843       1.1  christos 			return -1;
    844       1.1  christos 		memcpy(tmp->buffer, chain->buffer + chain->misalign,
    845       1.1  christos 			chain->off);
    846       1.1  christos 		tmp->off = chain->off;
    847       1.1  christos 		*src->last_with_datap = tmp;
    848       1.1  christos 		src->last = tmp;
    849       1.1  christos 		chain->misalign += chain->off;
    850       1.1  christos 		chain->off = 0;
    851       1.1  christos 	} else {
    852       1.1  christos 		src->last = *src->last_with_datap;
    853       1.1  christos 		*pinned = NULL;
    854       1.1  christos 	}
    855       1.1  christos 
    856       1.1  christos 	return 0;
    857       1.1  christos }
    858       1.1  christos 
    859       1.1  christos static inline void
    860       1.1  christos RESTORE_PINNED(struct evbuffer *src, struct evbuffer_chain *pinned,
    861       1.1  christos 		struct evbuffer_chain *last)
    862       1.1  christos {
    863       1.1  christos 	ASSERT_EVBUFFER_LOCKED(src);
    864       1.1  christos 
    865       1.1  christos 	if (!pinned) {
    866       1.1  christos 		ZERO_CHAIN(src);
    867       1.1  christos 		return;
    868       1.1  christos 	}
    869       1.1  christos 
    870       1.1  christos 	src->first = pinned;
    871       1.1  christos 	src->last = last;
    872       1.1  christos 	src->last_with_datap = &src->first;
    873       1.1  christos 	src->total_len = 0;
    874       1.1  christos }
    875       1.1  christos 
    876       1.1  christos static inline void
    877       1.1  christos COPY_CHAIN(struct evbuffer *dst, struct evbuffer *src)
    878       1.1  christos {
    879       1.1  christos 	ASSERT_EVBUFFER_LOCKED(dst);
    880       1.1  christos 	ASSERT_EVBUFFER_LOCKED(src);
    881       1.1  christos 	dst->first = src->first;
    882       1.1  christos 	if (src->last_with_datap == &src->first)
    883       1.1  christos 		dst->last_with_datap = &dst->first;
    884       1.1  christos 	else
    885       1.1  christos 		dst->last_with_datap = src->last_with_datap;
    886       1.1  christos 	dst->last = src->last;
    887       1.1  christos 	dst->total_len = src->total_len;
    888       1.1  christos }
    889       1.1  christos 
    890       1.1  christos static void
    891       1.1  christos APPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
    892       1.1  christos {
    893  1.1.1.10  christos 	struct evbuffer_chain **chp;
    894  1.1.1.10  christos 
    895       1.1  christos 	ASSERT_EVBUFFER_LOCKED(dst);
    896       1.1  christos 	ASSERT_EVBUFFER_LOCKED(src);
    897  1.1.1.10  christos 
    898  1.1.1.10  christos 	chp = evbuffer_free_trailing_empty_chains(dst);
    899  1.1.1.10  christos 	*chp = src->first;
    900  1.1.1.10  christos 
    901       1.1  christos 	if (src->last_with_datap == &src->first)
    902  1.1.1.10  christos 		dst->last_with_datap = chp;
    903       1.1  christos 	else
    904       1.1  christos 		dst->last_with_datap = src->last_with_datap;
    905       1.1  christos 	dst->last = src->last;
    906       1.1  christos 	dst->total_len += src->total_len;
    907       1.1  christos }
    908       1.1  christos 
    909       1.1  christos static inline void
    910       1.1  christos APPEND_CHAIN_MULTICAST(struct evbuffer *dst, struct evbuffer *src)
    911       1.1  christos {
    912       1.1  christos 	struct evbuffer_chain *tmp;
    913       1.1  christos 	struct evbuffer_chain *chain = src->first;
    914       1.1  christos 	struct evbuffer_multicast_parent *extra;
    915       1.1  christos 
    916       1.1  christos 	ASSERT_EVBUFFER_LOCKED(dst);
    917       1.1  christos 	ASSERT_EVBUFFER_LOCKED(src);
    918       1.1  christos 
    919       1.1  christos 	for (; chain; chain = chain->next) {
    920       1.1  christos 		if (!chain->off || chain->flags & EVBUFFER_DANGLING) {
    921       1.1  christos 			/* skip empty chains */
    922       1.1  christos 			continue;
    923       1.1  christos 		}
    924       1.1  christos 
    925       1.1  christos 		tmp = evbuffer_chain_new(sizeof(struct evbuffer_multicast_parent));
    926       1.1  christos 		if (!tmp) {
    927       1.1  christos 			event_warn("%s: out of memory", __func__);
    928       1.1  christos 			return;
    929       1.1  christos 		}
    930       1.1  christos 		extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
    931       1.1  christos 		/* reference evbuffer containing source chain so it
    932       1.1  christos 		 * doesn't get released while the chain is still
    933       1.1  christos 		 * being referenced to */
    934       1.1  christos 		evbuffer_incref_(src);
    935       1.1  christos 		extra->source = src;
    936       1.1  christos 		/* reference source chain which now becomes immutable */
    937       1.1  christos 		evbuffer_chain_incref(chain);
    938       1.1  christos 		extra->parent = chain;
    939       1.1  christos 		chain->flags |= EVBUFFER_IMMUTABLE;
    940       1.1  christos 		tmp->buffer_len = chain->buffer_len;
    941       1.1  christos 		tmp->misalign = chain->misalign;
    942       1.1  christos 		tmp->off = chain->off;
    943       1.1  christos 		tmp->flags |= EVBUFFER_MULTICAST|EVBUFFER_IMMUTABLE;
    944       1.1  christos 		tmp->buffer = chain->buffer;
    945       1.1  christos 		evbuffer_chain_insert(dst, tmp);
    946       1.1  christos 	}
    947       1.1  christos }
    948       1.1  christos 
    949       1.1  christos static void
    950       1.1  christos PREPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
    951       1.1  christos {
    952       1.1  christos 	ASSERT_EVBUFFER_LOCKED(dst);
    953       1.1  christos 	ASSERT_EVBUFFER_LOCKED(src);
    954       1.1  christos 	src->last->next = dst->first;
    955       1.1  christos 	dst->first = src->first;
    956       1.1  christos 	dst->total_len += src->total_len;
    957       1.1  christos 	if (*dst->last_with_datap == NULL) {
    958       1.1  christos 		if (src->last_with_datap == &(src)->first)
    959       1.1  christos 			dst->last_with_datap = &dst->first;
    960       1.1  christos 		else
    961       1.1  christos 			dst->last_with_datap = src->last_with_datap;
    962       1.1  christos 	} else if (dst->last_with_datap == &dst->first) {
    963       1.1  christos 		dst->last_with_datap = &src->last->next;
    964       1.1  christos 	}
    965       1.1  christos }
    966       1.1  christos 
    967       1.1  christos int
    968       1.1  christos evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
    969       1.1  christos {
    970       1.1  christos 	struct evbuffer_chain *pinned, *last;
    971       1.1  christos 	size_t in_total_len, out_total_len;
    972       1.1  christos 	int result = 0;
    973       1.1  christos 
    974       1.1  christos 	EVBUFFER_LOCK2(inbuf, outbuf);
    975       1.1  christos 	in_total_len = inbuf->total_len;
    976       1.1  christos 	out_total_len = outbuf->total_len;
    977       1.1  christos 
    978       1.1  christos 	if (in_total_len == 0 || outbuf == inbuf)
    979       1.1  christos 		goto done;
    980       1.1  christos 
    981       1.1  christos 	if (outbuf->freeze_end || inbuf->freeze_start) {
    982       1.1  christos 		result = -1;
    983       1.1  christos 		goto done;
    984       1.1  christos 	}
    985       1.1  christos 
    986       1.1  christos 	if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
    987       1.1  christos 		result = -1;
    988       1.1  christos 		goto done;
    989       1.1  christos 	}
    990       1.1  christos 
    991       1.1  christos 	if (out_total_len == 0) {
    992       1.1  christos 		/* There might be an empty chain at the start of outbuf; free
    993       1.1  christos 		 * it. */
    994       1.1  christos 		evbuffer_free_all_chains(outbuf->first);
    995       1.1  christos 		COPY_CHAIN(outbuf, inbuf);
    996       1.1  christos 	} else {
    997       1.1  christos 		APPEND_CHAIN(outbuf, inbuf);
    998       1.1  christos 	}
    999       1.1  christos 
   1000       1.1  christos 	RESTORE_PINNED(inbuf, pinned, last);
   1001       1.1  christos 
   1002       1.1  christos 	inbuf->n_del_for_cb += in_total_len;
   1003       1.1  christos 	outbuf->n_add_for_cb += in_total_len;
   1004       1.1  christos 
   1005       1.1  christos 	evbuffer_invoke_callbacks_(inbuf);
   1006       1.1  christos 	evbuffer_invoke_callbacks_(outbuf);
   1007       1.1  christos 
   1008       1.1  christos done:
   1009       1.1  christos 	EVBUFFER_UNLOCK2(inbuf, outbuf);
   1010       1.1  christos 	return result;
   1011       1.1  christos }
   1012       1.1  christos 
   1013       1.1  christos int
   1014       1.1  christos evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)
   1015       1.1  christos {
   1016       1.1  christos 	size_t in_total_len, out_total_len;
   1017       1.1  christos 	struct evbuffer_chain *chain;
   1018       1.1  christos 	int result = 0;
   1019       1.1  christos 
   1020       1.1  christos 	EVBUFFER_LOCK2(inbuf, outbuf);
   1021       1.1  christos 	in_total_len = inbuf->total_len;
   1022       1.1  christos 	out_total_len = outbuf->total_len;
   1023       1.1  christos 	chain = inbuf->first;
   1024       1.1  christos 
   1025       1.1  christos 	if (in_total_len == 0)
   1026       1.1  christos 		goto done;
   1027       1.1  christos 
   1028       1.1  christos 	if (outbuf->freeze_end || outbuf == inbuf) {
   1029       1.1  christos 		result = -1;
   1030       1.1  christos 		goto done;
   1031       1.1  christos 	}
   1032       1.1  christos 
   1033       1.1  christos 	for (; chain; chain = chain->next) {
   1034       1.1  christos 		if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE|EVBUFFER_MULTICAST)) != 0) {
   1035       1.1  christos 			/* chain type can not be referenced */
   1036       1.1  christos 			result = -1;
   1037       1.1  christos 			goto done;
   1038       1.1  christos 		}
   1039       1.1  christos 	}
   1040       1.1  christos 
   1041       1.1  christos 	if (out_total_len == 0) {
   1042       1.1  christos 		/* There might be an empty chain at the start of outbuf; free
   1043       1.1  christos 		 * it. */
   1044       1.1  christos 		evbuffer_free_all_chains(outbuf->first);
   1045       1.1  christos 	}
   1046       1.1  christos 	APPEND_CHAIN_MULTICAST(outbuf, inbuf);
   1047       1.1  christos 
   1048       1.1  christos 	outbuf->n_add_for_cb += in_total_len;
   1049       1.1  christos 	evbuffer_invoke_callbacks_(outbuf);
   1050       1.1  christos 
   1051       1.1  christos done:
   1052       1.1  christos 	EVBUFFER_UNLOCK2(inbuf, outbuf);
   1053       1.1  christos 	return result;
   1054       1.1  christos }
   1055       1.1  christos 
   1056       1.1  christos int
   1057       1.1  christos evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
   1058       1.1  christos {
   1059       1.1  christos 	struct evbuffer_chain *pinned, *last;
   1060       1.1  christos 	size_t in_total_len, out_total_len;
   1061       1.1  christos 	int result = 0;
   1062       1.1  christos 
   1063       1.1  christos 	EVBUFFER_LOCK2(inbuf, outbuf);
   1064       1.1  christos 
   1065       1.1  christos 	in_total_len = inbuf->total_len;
   1066       1.1  christos 	out_total_len = outbuf->total_len;
   1067       1.1  christos 
   1068       1.1  christos 	if (!in_total_len || inbuf == outbuf)
   1069       1.1  christos 		goto done;
   1070       1.1  christos 
   1071       1.1  christos 	if (outbuf->freeze_start || inbuf->freeze_start) {
   1072       1.1  christos 		result = -1;
   1073       1.1  christos 		goto done;
   1074       1.1  christos 	}
   1075       1.1  christos 
   1076       1.1  christos 	if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
   1077       1.1  christos 		result = -1;
   1078       1.1  christos 		goto done;
   1079       1.1  christos 	}
   1080       1.1  christos 
   1081       1.1  christos 	if (out_total_len == 0) {
   1082       1.1  christos 		/* There might be an empty chain at the start of outbuf; free
   1083       1.1  christos 		 * it. */
   1084       1.1  christos 		evbuffer_free_all_chains(outbuf->first);
   1085       1.1  christos 		COPY_CHAIN(outbuf, inbuf);
   1086       1.1  christos 	} else {
   1087       1.1  christos 		PREPEND_CHAIN(outbuf, inbuf);
   1088       1.1  christos 	}
   1089       1.1  christos 
   1090       1.1  christos 	RESTORE_PINNED(inbuf, pinned, last);
   1091       1.1  christos 
   1092       1.1  christos 	inbuf->n_del_for_cb += in_total_len;
   1093       1.1  christos 	outbuf->n_add_for_cb += in_total_len;
   1094       1.1  christos 
   1095       1.1  christos 	evbuffer_invoke_callbacks_(inbuf);
   1096       1.1  christos 	evbuffer_invoke_callbacks_(outbuf);
   1097       1.1  christos done:
   1098       1.1  christos 	EVBUFFER_UNLOCK2(inbuf, outbuf);
   1099       1.1  christos 	return result;
   1100       1.1  christos }
   1101       1.1  christos 
   1102       1.1  christos int
   1103       1.1  christos evbuffer_drain(struct evbuffer *buf, size_t len)
   1104       1.1  christos {
   1105       1.1  christos 	struct evbuffer_chain *chain, *next;
   1106       1.1  christos 	size_t remaining, old_len;
   1107       1.1  christos 	int result = 0;
   1108       1.1  christos 
   1109       1.1  christos 	EVBUFFER_LOCK(buf);
   1110       1.1  christos 	old_len = buf->total_len;
   1111       1.1  christos 
   1112       1.1  christos 	if (old_len == 0)
   1113       1.1  christos 		goto done;
   1114       1.1  christos 
   1115       1.1  christos 	if (buf->freeze_start) {
   1116       1.1  christos 		result = -1;
   1117       1.1  christos 		goto done;
   1118       1.1  christos 	}
   1119       1.1  christos 
   1120       1.1  christos 	if (len >= old_len && !HAS_PINNED_R(buf)) {
   1121       1.1  christos 		len = old_len;
   1122       1.1  christos 		for (chain = buf->first; chain != NULL; chain = next) {
   1123       1.1  christos 			next = chain->next;
   1124       1.1  christos 			evbuffer_chain_free(chain);
   1125       1.1  christos 		}
   1126       1.1  christos 
   1127       1.1  christos 		ZERO_CHAIN(buf);
   1128       1.1  christos 	} else {
   1129       1.1  christos 		if (len >= old_len)
   1130       1.1  christos 			len = old_len;
   1131       1.1  christos 
   1132       1.1  christos 		buf->total_len -= len;
   1133       1.1  christos 		remaining = len;
   1134       1.1  christos 		for (chain = buf->first;
   1135       1.1  christos 		     remaining >= chain->off;
   1136       1.1  christos 		     chain = next) {
   1137       1.1  christos 			next = chain->next;
   1138       1.1  christos 			remaining -= chain->off;
   1139       1.1  christos 
   1140       1.1  christos 			if (chain == *buf->last_with_datap) {
   1141       1.1  christos 				buf->last_with_datap = &buf->first;
   1142       1.1  christos 			}
   1143       1.1  christos 			if (&chain->next == buf->last_with_datap)
   1144       1.1  christos 				buf->last_with_datap = &buf->first;
   1145       1.1  christos 
   1146       1.1  christos 			if (CHAIN_PINNED_R(chain)) {
   1147       1.1  christos 				EVUTIL_ASSERT(remaining == 0);
   1148       1.1  christos 				chain->misalign += chain->off;
   1149       1.1  christos 				chain->off = 0;
   1150       1.1  christos 				break;
   1151       1.1  christos 			} else
   1152       1.1  christos 				evbuffer_chain_free(chain);
   1153       1.1  christos 		}
   1154       1.1  christos 
   1155       1.1  christos 		buf->first = chain;
   1156  1.1.1.10  christos 		EVUTIL_ASSERT(remaining <= chain->off);
   1157       1.1  christos 		chain->misalign += remaining;
   1158       1.1  christos 		chain->off -= remaining;
   1159       1.1  christos 	}
   1160       1.1  christos 
   1161       1.1  christos 	buf->n_del_for_cb += len;
   1162       1.1  christos 	/* Tell someone about changes in this buffer */
   1163       1.1  christos 	evbuffer_invoke_callbacks_(buf);
   1164       1.1  christos 
   1165       1.1  christos done:
   1166       1.1  christos 	EVBUFFER_UNLOCK(buf);
   1167       1.1  christos 	return result;
   1168       1.1  christos }
   1169       1.1  christos 
   1170       1.1  christos /* Reads data from an event buffer and drains the bytes read */
   1171       1.1  christos int
   1172       1.1  christos evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
   1173       1.1  christos {
   1174       1.1  christos 	ev_ssize_t n;
   1175       1.1  christos 	EVBUFFER_LOCK(buf);
   1176       1.1  christos 	n = evbuffer_copyout_from(buf, NULL, data_out, datlen);
   1177       1.1  christos 	if (n > 0) {
   1178       1.1  christos 		if (evbuffer_drain(buf, n)<0)
   1179       1.1  christos 			n = -1;
   1180       1.1  christos 	}
   1181       1.1  christos 	EVBUFFER_UNLOCK(buf);
   1182       1.1  christos 	return (int)n;
   1183       1.1  christos }
   1184       1.1  christos 
   1185       1.1  christos ev_ssize_t
   1186       1.1  christos evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
   1187       1.1  christos {
   1188       1.1  christos 	return evbuffer_copyout_from(buf, NULL, data_out, datlen);
   1189       1.1  christos }
   1190       1.1  christos 
   1191       1.1  christos ev_ssize_t
   1192       1.1  christos evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
   1193       1.1  christos     void *data_out, size_t datlen)
   1194       1.1  christos {
   1195       1.1  christos 	/*XXX fails badly on sendfile case. */
   1196       1.1  christos 	struct evbuffer_chain *chain;
   1197       1.1  christos 	char *data = data_out;
   1198       1.1  christos 	size_t nread;
   1199       1.1  christos 	ev_ssize_t result = 0;
   1200       1.1  christos 	size_t pos_in_chain;
   1201       1.1  christos 
   1202       1.1  christos 	EVBUFFER_LOCK(buf);
   1203       1.1  christos 
   1204       1.1  christos 	if (pos) {
   1205   1.1.1.3  christos 		if (datlen > (size_t)(EV_SSIZE_MAX - pos->pos)) {
   1206   1.1.1.3  christos 			result = -1;
   1207   1.1.1.3  christos 			goto done;
   1208   1.1.1.3  christos 		}
   1209       1.1  christos 		chain = pos->internal_.chain;
   1210       1.1  christos 		pos_in_chain = pos->internal_.pos_in_chain;
   1211       1.1  christos 		if (datlen + pos->pos > buf->total_len)
   1212       1.1  christos 			datlen = buf->total_len - pos->pos;
   1213       1.1  christos 	} else {
   1214       1.1  christos 		chain = buf->first;
   1215       1.1  christos 		pos_in_chain = 0;
   1216       1.1  christos 		if (datlen > buf->total_len)
   1217       1.1  christos 			datlen = buf->total_len;
   1218       1.1  christos 	}
   1219       1.1  christos 
   1220       1.1  christos 
   1221       1.1  christos 	if (datlen == 0)
   1222       1.1  christos 		goto done;
   1223       1.1  christos 
   1224       1.1  christos 	if (buf->freeze_start) {
   1225       1.1  christos 		result = -1;
   1226       1.1  christos 		goto done;
   1227       1.1  christos 	}
   1228       1.1  christos 
   1229       1.1  christos 	nread = datlen;
   1230       1.1  christos 
   1231       1.1  christos 	while (datlen && datlen >= chain->off - pos_in_chain) {
   1232       1.1  christos 		size_t copylen = chain->off - pos_in_chain;
   1233       1.1  christos 		memcpy(data,
   1234       1.1  christos 		    chain->buffer + chain->misalign + pos_in_chain,
   1235       1.1  christos 		    copylen);
   1236       1.1  christos 		data += copylen;
   1237       1.1  christos 		datlen -= copylen;
   1238       1.1  christos 
   1239       1.1  christos 		chain = chain->next;
   1240       1.1  christos 		pos_in_chain = 0;
   1241       1.1  christos 		EVUTIL_ASSERT(chain || datlen==0);
   1242       1.1  christos 	}
   1243       1.1  christos 
   1244       1.1  christos 	if (datlen) {
   1245       1.1  christos 		EVUTIL_ASSERT(chain);
   1246   1.1.1.3  christos 		EVUTIL_ASSERT(datlen+pos_in_chain <= chain->off);
   1247   1.1.1.3  christos 
   1248       1.1  christos 		memcpy(data, chain->buffer + chain->misalign + pos_in_chain,
   1249       1.1  christos 		    datlen);
   1250       1.1  christos 	}
   1251       1.1  christos 
   1252       1.1  christos 	result = nread;
   1253       1.1  christos done:
   1254       1.1  christos 	EVBUFFER_UNLOCK(buf);
   1255       1.1  christos 	return result;
   1256       1.1  christos }
   1257       1.1  christos 
   1258       1.1  christos /* reads data from the src buffer to the dst buffer, avoids memcpy as
   1259       1.1  christos  * possible. */
   1260       1.1  christos /*  XXXX should return ev_ssize_t */
   1261       1.1  christos int
   1262       1.1  christos evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
   1263       1.1  christos     size_t datlen)
   1264       1.1  christos {
   1265       1.1  christos 	/*XXX We should have an option to force this to be zero-copy.*/
   1266       1.1  christos 
   1267       1.1  christos 	/*XXX can fail badly on sendfile case. */
   1268       1.1  christos 	struct evbuffer_chain *chain, *previous;
   1269       1.1  christos 	size_t nread = 0;
   1270       1.1  christos 	int result;
   1271       1.1  christos 
   1272       1.1  christos 	EVBUFFER_LOCK2(src, dst);
   1273       1.1  christos 
   1274       1.1  christos 	chain = previous = src->first;
   1275       1.1  christos 
   1276       1.1  christos 	if (datlen == 0 || dst == src) {
   1277       1.1  christos 		result = 0;
   1278       1.1  christos 		goto done;
   1279       1.1  christos 	}
   1280       1.1  christos 
   1281       1.1  christos 	if (dst->freeze_end || src->freeze_start) {
   1282       1.1  christos 		result = -1;
   1283       1.1  christos 		goto done;
   1284       1.1  christos 	}
   1285       1.1  christos 
   1286       1.1  christos 	/* short-cut if there is no more data buffered */
   1287       1.1  christos 	if (datlen >= src->total_len) {
   1288       1.1  christos 		datlen = src->total_len;
   1289       1.1  christos 		evbuffer_add_buffer(dst, src);
   1290       1.1  christos 		result = (int)datlen; /*XXXX should return ev_ssize_t*/
   1291       1.1  christos 		goto done;
   1292       1.1  christos 	}
   1293       1.1  christos 
   1294       1.1  christos 	/* removes chains if possible */
   1295       1.1  christos 	while (chain->off <= datlen) {
   1296       1.1  christos 		/* We can't remove the last with data from src unless we
   1297       1.1  christos 		 * remove all chains, in which case we would have done the if
   1298       1.1  christos 		 * block above */
   1299       1.1  christos 		EVUTIL_ASSERT(chain != *src->last_with_datap);
   1300       1.1  christos 		nread += chain->off;
   1301       1.1  christos 		datlen -= chain->off;
   1302       1.1  christos 		previous = chain;
   1303       1.1  christos 		if (src->last_with_datap == &chain->next)
   1304       1.1  christos 			src->last_with_datap = &src->first;
   1305       1.1  christos 		chain = chain->next;
   1306       1.1  christos 	}
   1307       1.1  christos 
   1308  1.1.1.10  christos 	if (chain != src->first) {
   1309       1.1  christos 		/* we can remove the chain */
   1310       1.1  christos 		struct evbuffer_chain **chp;
   1311       1.1  christos 		chp = evbuffer_free_trailing_empty_chains(dst);
   1312       1.1  christos 
   1313       1.1  christos 		if (dst->first == NULL) {
   1314       1.1  christos 			dst->first = src->first;
   1315       1.1  christos 		} else {
   1316       1.1  christos 			*chp = src->first;
   1317       1.1  christos 		}
   1318       1.1  christos 		dst->last = previous;
   1319       1.1  christos 		previous->next = NULL;
   1320       1.1  christos 		src->first = chain;
   1321       1.1  christos 		advance_last_with_data(dst);
   1322       1.1  christos 
   1323       1.1  christos 		dst->total_len += nread;
   1324       1.1  christos 		dst->n_add_for_cb += nread;
   1325       1.1  christos 	}
   1326       1.1  christos 
   1327       1.1  christos 	/* we know that there is more data in the src buffer than
   1328       1.1  christos 	 * we want to read, so we manually drain the chain */
   1329       1.1  christos 	evbuffer_add(dst, chain->buffer + chain->misalign, datlen);
   1330       1.1  christos 	chain->misalign += datlen;
   1331       1.1  christos 	chain->off -= datlen;
   1332       1.1  christos 	nread += datlen;
   1333       1.1  christos 
   1334       1.1  christos 	/* You might think we would want to increment dst->n_add_for_cb
   1335       1.1  christos 	 * here too.  But evbuffer_add above already took care of that.
   1336       1.1  christos 	 */
   1337       1.1  christos 	src->total_len -= nread;
   1338       1.1  christos 	src->n_del_for_cb += nread;
   1339       1.1  christos 
   1340       1.1  christos 	if (nread) {
   1341       1.1  christos 		evbuffer_invoke_callbacks_(dst);
   1342       1.1  christos 		evbuffer_invoke_callbacks_(src);
   1343       1.1  christos 	}
   1344       1.1  christos 	result = (int)nread;/*XXXX should change return type */
   1345       1.1  christos 
   1346       1.1  christos done:
   1347       1.1  christos 	EVBUFFER_UNLOCK2(src, dst);
   1348       1.1  christos 	return result;
   1349       1.1  christos }
   1350       1.1  christos 
   1351       1.1  christos unsigned char *
   1352       1.1  christos evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
   1353       1.1  christos {
   1354       1.1  christos 	struct evbuffer_chain *chain, *next, *tmp, *last_with_data;
   1355       1.1  christos 	unsigned char *buffer, *result = NULL;
   1356       1.1  christos 	ev_ssize_t remaining;
   1357       1.1  christos 	int removed_last_with_data = 0;
   1358       1.1  christos 	int removed_last_with_datap = 0;
   1359       1.1  christos 
   1360       1.1  christos 	EVBUFFER_LOCK(buf);
   1361       1.1  christos 
   1362       1.1  christos 	chain = buf->first;
   1363       1.1  christos 
   1364       1.1  christos 	if (size < 0)
   1365       1.1  christos 		size = buf->total_len;
   1366       1.1  christos 	/* if size > buf->total_len, we cannot guarantee to the user that she
   1367       1.1  christos 	 * is going to have a long enough buffer afterwards; so we return
   1368       1.1  christos 	 * NULL */
   1369       1.1  christos 	if (size == 0 || (size_t)size > buf->total_len)
   1370       1.1  christos 		goto done;
   1371       1.1  christos 
   1372       1.1  christos 	/* No need to pull up anything; the first size bytes are
   1373       1.1  christos 	 * already here. */
   1374       1.1  christos 	if (chain->off >= (size_t)size) {
   1375       1.1  christos 		result = chain->buffer + chain->misalign;
   1376       1.1  christos 		goto done;
   1377       1.1  christos 	}
   1378       1.1  christos 
   1379       1.1  christos 	/* Make sure that none of the chains we need to copy from is pinned. */
   1380       1.1  christos 	remaining = size - chain->off;
   1381       1.1  christos 	EVUTIL_ASSERT(remaining >= 0);
   1382       1.1  christos 	for (tmp=chain->next; tmp; tmp=tmp->next) {
   1383       1.1  christos 		if (CHAIN_PINNED(tmp))
   1384       1.1  christos 			goto done;
   1385       1.1  christos 		if (tmp->off >= (size_t)remaining)
   1386       1.1  christos 			break;
   1387       1.1  christos 		remaining -= tmp->off;
   1388       1.1  christos 	}
   1389       1.1  christos 
   1390       1.1  christos 	if (CHAIN_PINNED(chain)) {
   1391       1.1  christos 		size_t old_off = chain->off;
   1392       1.1  christos 		if (CHAIN_SPACE_LEN(chain) < size - chain->off) {
   1393       1.1  christos 			/* not enough room at end of chunk. */
   1394       1.1  christos 			goto done;
   1395       1.1  christos 		}
   1396       1.1  christos 		buffer = CHAIN_SPACE_PTR(chain);
   1397       1.1  christos 		tmp = chain;
   1398       1.1  christos 		tmp->off = size;
   1399       1.1  christos 		size -= old_off;
   1400       1.1  christos 		chain = chain->next;
   1401       1.1  christos 	} else if (chain->buffer_len - chain->misalign >= (size_t)size) {
   1402       1.1  christos 		/* already have enough space in the first chain */
   1403       1.1  christos 		size_t old_off = chain->off;
   1404       1.1  christos 		buffer = chain->buffer + chain->misalign + chain->off;
   1405       1.1  christos 		tmp = chain;
   1406       1.1  christos 		tmp->off = size;
   1407       1.1  christos 		size -= old_off;
   1408       1.1  christos 		chain = chain->next;
   1409       1.1  christos 	} else {
   1410       1.1  christos 		if ((tmp = evbuffer_chain_new(size)) == NULL) {
   1411       1.1  christos 			event_warn("%s: out of memory", __func__);
   1412       1.1  christos 			goto done;
   1413       1.1  christos 		}
   1414       1.1  christos 		buffer = tmp->buffer;
   1415       1.1  christos 		tmp->off = size;
   1416       1.1  christos 		buf->first = tmp;
   1417       1.1  christos 	}
   1418       1.1  christos 
   1419       1.1  christos 	/* TODO(niels): deal with buffers that point to NULL like sendfile */
   1420       1.1  christos 
   1421       1.1  christos 	/* Copy and free every chunk that will be entirely pulled into tmp */
   1422       1.1  christos 	last_with_data = *buf->last_with_datap;
   1423       1.1  christos 	for (; chain != NULL && (size_t)size >= chain->off; chain = next) {
   1424       1.1  christos 		next = chain->next;
   1425       1.1  christos 
   1426  1.1.1.10  christos 		if (chain->buffer) {
   1427  1.1.1.10  christos 			memcpy(buffer, chain->buffer + chain->misalign, chain->off);
   1428  1.1.1.10  christos 			size -= chain->off;
   1429  1.1.1.10  christos 			buffer += chain->off;
   1430  1.1.1.10  christos 		}
   1431       1.1  christos 		if (chain == last_with_data)
   1432       1.1  christos 			removed_last_with_data = 1;
   1433       1.1  christos 		if (&chain->next == buf->last_with_datap)
   1434       1.1  christos 			removed_last_with_datap = 1;
   1435       1.1  christos 
   1436       1.1  christos 		evbuffer_chain_free(chain);
   1437       1.1  christos 	}
   1438       1.1  christos 
   1439       1.1  christos 	if (chain != NULL) {
   1440       1.1  christos 		memcpy(buffer, chain->buffer + chain->misalign, size);
   1441       1.1  christos 		chain->misalign += size;
   1442       1.1  christos 		chain->off -= size;
   1443       1.1  christos 	} else {
   1444       1.1  christos 		buf->last = tmp;
   1445       1.1  christos 	}
   1446       1.1  christos 
   1447       1.1  christos 	tmp->next = chain;
   1448       1.1  christos 
   1449       1.1  christos 	if (removed_last_with_data) {
   1450       1.1  christos 		buf->last_with_datap = &buf->first;
   1451       1.1  christos 	} else if (removed_last_with_datap) {
   1452       1.1  christos 		if (buf->first->next && buf->first->next->off)
   1453       1.1  christos 			buf->last_with_datap = &buf->first->next;
   1454       1.1  christos 		else
   1455       1.1  christos 			buf->last_with_datap = &buf->first;
   1456       1.1  christos 	}
   1457       1.1  christos 
   1458       1.1  christos 	result = (tmp->buffer + tmp->misalign);
   1459       1.1  christos 
   1460       1.1  christos done:
   1461       1.1  christos 	EVBUFFER_UNLOCK(buf);
   1462       1.1  christos 	return result;
   1463       1.1  christos }
   1464       1.1  christos 
   1465       1.1  christos /*
   1466       1.1  christos  * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
   1467       1.1  christos  * The returned buffer needs to be freed by the called.
   1468       1.1  christos  */
   1469       1.1  christos char *
   1470       1.1  christos evbuffer_readline(struct evbuffer *buffer)
   1471       1.1  christos {
   1472       1.1  christos 	return evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY);
   1473       1.1  christos }
   1474       1.1  christos 
   1475       1.1  christos static inline ev_ssize_t
   1476       1.1  christos evbuffer_strchr(struct evbuffer_ptr *it, const char chr)
   1477       1.1  christos {
   1478       1.1  christos 	struct evbuffer_chain *chain = it->internal_.chain;
   1479       1.1  christos 	size_t i = it->internal_.pos_in_chain;
   1480       1.1  christos 	while (chain != NULL) {
   1481       1.1  christos 		char *buffer = (char *)chain->buffer + chain->misalign;
   1482       1.1  christos 		char *cp = memchr(buffer+i, chr, chain->off-i);
   1483       1.1  christos 		if (cp) {
   1484       1.1  christos 			it->internal_.chain = chain;
   1485       1.1  christos 			it->internal_.pos_in_chain = cp - buffer;
   1486       1.1  christos 			it->pos += (cp - buffer - i);
   1487       1.1  christos 			return it->pos;
   1488       1.1  christos 		}
   1489       1.1  christos 		it->pos += chain->off - i;
   1490       1.1  christos 		i = 0;
   1491       1.1  christos 		chain = chain->next;
   1492       1.1  christos 	}
   1493       1.1  christos 
   1494       1.1  christos 	return (-1);
   1495       1.1  christos }
   1496       1.1  christos 
   1497       1.1  christos static inline char *
   1498       1.1  christos find_eol_char(char *s, size_t len)
   1499       1.1  christos {
   1500       1.1  christos #define CHUNK_SZ 128
   1501       1.1  christos 	/* Lots of benchmarking found this approach to be faster in practice
   1502       1.1  christos 	 * than doing two memchrs over the whole buffer, doin a memchr on each
   1503       1.1  christos 	 * char of the buffer, or trying to emulate memchr by hand. */
   1504       1.1  christos 	char *s_end, *cr, *lf;
   1505       1.1  christos 	s_end = s+len;
   1506       1.1  christos 	while (s < s_end) {
   1507       1.1  christos 		size_t chunk = (s + CHUNK_SZ < s_end) ? CHUNK_SZ : (s_end - s);
   1508       1.1  christos 		cr = memchr(s, '\r', chunk);
   1509       1.1  christos 		lf = memchr(s, '\n', chunk);
   1510       1.1  christos 		if (cr) {
   1511       1.1  christos 			if (lf && lf < cr)
   1512       1.1  christos 				return lf;
   1513       1.1  christos 			return cr;
   1514       1.1  christos 		} else if (lf) {
   1515       1.1  christos 			return lf;
   1516       1.1  christos 		}
   1517       1.1  christos 		s += CHUNK_SZ;
   1518       1.1  christos 	}
   1519       1.1  christos 
   1520       1.1  christos 	return NULL;
   1521       1.1  christos #undef CHUNK_SZ
   1522       1.1  christos }
   1523       1.1  christos 
   1524       1.1  christos static ev_ssize_t
   1525       1.1  christos evbuffer_find_eol_char(struct evbuffer_ptr *it)
   1526       1.1  christos {
   1527       1.1  christos 	struct evbuffer_chain *chain = it->internal_.chain;
   1528       1.1  christos 	size_t i = it->internal_.pos_in_chain;
   1529       1.1  christos 	while (chain != NULL) {
   1530       1.1  christos 		char *buffer = (char *)chain->buffer + chain->misalign;
   1531       1.1  christos 		char *cp = find_eol_char(buffer+i, chain->off-i);
   1532       1.1  christos 		if (cp) {
   1533       1.1  christos 			it->internal_.chain = chain;
   1534       1.1  christos 			it->internal_.pos_in_chain = cp - buffer;
   1535       1.1  christos 			it->pos += (cp - buffer) - i;
   1536       1.1  christos 			return it->pos;
   1537       1.1  christos 		}
   1538       1.1  christos 		it->pos += chain->off - i;
   1539       1.1  christos 		i = 0;
   1540       1.1  christos 		chain = chain->next;
   1541       1.1  christos 	}
   1542       1.1  christos 
   1543       1.1  christos 	return (-1);
   1544       1.1  christos }
   1545       1.1  christos 
   1546  1.1.1.10  christos static inline size_t
   1547       1.1  christos evbuffer_strspn(
   1548       1.1  christos 	struct evbuffer_ptr *ptr, const char *chrset)
   1549       1.1  christos {
   1550  1.1.1.10  christos 	size_t count = 0;
   1551       1.1  christos 	struct evbuffer_chain *chain = ptr->internal_.chain;
   1552       1.1  christos 	size_t i = ptr->internal_.pos_in_chain;
   1553       1.1  christos 
   1554       1.1  christos 	if (!chain)
   1555       1.1  christos 		return 0;
   1556       1.1  christos 
   1557       1.1  christos 	while (1) {
   1558       1.1  christos 		char *buffer = (char *)chain->buffer + chain->misalign;
   1559       1.1  christos 		for (; i < chain->off; ++i) {
   1560       1.1  christos 			const char *p = chrset;
   1561       1.1  christos 			while (*p) {
   1562       1.1  christos 				if (buffer[i] == *p++)
   1563       1.1  christos 					goto next;
   1564       1.1  christos 			}
   1565       1.1  christos 			ptr->internal_.chain = chain;
   1566       1.1  christos 			ptr->internal_.pos_in_chain = i;
   1567       1.1  christos 			ptr->pos += count;
   1568       1.1  christos 			return count;
   1569       1.1  christos 		next:
   1570       1.1  christos 			++count;
   1571       1.1  christos 		}
   1572       1.1  christos 		i = 0;
   1573       1.1  christos 
   1574       1.1  christos 		if (! chain->next) {
   1575       1.1  christos 			ptr->internal_.chain = chain;
   1576       1.1  christos 			ptr->internal_.pos_in_chain = i;
   1577       1.1  christos 			ptr->pos += count;
   1578       1.1  christos 			return count;
   1579       1.1  christos 		}
   1580       1.1  christos 
   1581       1.1  christos 		chain = chain->next;
   1582       1.1  christos 	}
   1583       1.1  christos }
   1584       1.1  christos 
   1585       1.1  christos 
   1586       1.1  christos static inline int
   1587       1.1  christos evbuffer_getchr(struct evbuffer_ptr *it)
   1588       1.1  christos {
   1589       1.1  christos 	struct evbuffer_chain *chain = it->internal_.chain;
   1590       1.1  christos 	size_t off = it->internal_.pos_in_chain;
   1591       1.1  christos 
   1592       1.1  christos 	if (chain == NULL)
   1593       1.1  christos 		return -1;
   1594       1.1  christos 
   1595       1.1  christos 	return (unsigned char)chain->buffer[chain->misalign + off];
   1596       1.1  christos }
   1597       1.1  christos 
   1598       1.1  christos struct evbuffer_ptr
   1599       1.1  christos evbuffer_search_eol(struct evbuffer *buffer,
   1600       1.1  christos     struct evbuffer_ptr *start, size_t *eol_len_out,
   1601       1.1  christos     enum evbuffer_eol_style eol_style)
   1602       1.1  christos {
   1603       1.1  christos 	struct evbuffer_ptr it, it2;
   1604       1.1  christos 	size_t extra_drain = 0;
   1605       1.1  christos 	int ok = 0;
   1606       1.1  christos 
   1607       1.1  christos 	/* Avoid locking in trivial edge cases */
   1608       1.1  christos 	if (start && start->internal_.chain == NULL) {
   1609       1.1  christos 		PTR_NOT_FOUND(&it);
   1610       1.1  christos 		if (eol_len_out)
   1611       1.1  christos 			*eol_len_out = extra_drain;
   1612       1.1  christos 		return it;
   1613       1.1  christos 	}
   1614       1.1  christos 
   1615       1.1  christos 	EVBUFFER_LOCK(buffer);
   1616       1.1  christos 
   1617       1.1  christos 	if (start) {
   1618       1.1  christos 		memcpy(&it, start, sizeof(it));
   1619       1.1  christos 	} else {
   1620       1.1  christos 		it.pos = 0;
   1621       1.1  christos 		it.internal_.chain = buffer->first;
   1622       1.1  christos 		it.internal_.pos_in_chain = 0;
   1623       1.1  christos 	}
   1624       1.1  christos 
   1625       1.1  christos 	/* the eol_style determines our first stop character and how many
   1626       1.1  christos 	 * characters we are going to drain afterwards. */
   1627       1.1  christos 	switch (eol_style) {
   1628       1.1  christos 	case EVBUFFER_EOL_ANY:
   1629       1.1  christos 		if (evbuffer_find_eol_char(&it) < 0)
   1630       1.1  christos 			goto done;
   1631       1.1  christos 		memcpy(&it2, &it, sizeof(it));
   1632       1.1  christos 		extra_drain = evbuffer_strspn(&it2, "\r\n");
   1633       1.1  christos 		break;
   1634       1.1  christos 	case EVBUFFER_EOL_CRLF_STRICT: {
   1635       1.1  christos 		it = evbuffer_search(buffer, "\r\n", 2, &it);
   1636       1.1  christos 		if (it.pos < 0)
   1637       1.1  christos 			goto done;
   1638       1.1  christos 		extra_drain = 2;
   1639       1.1  christos 		break;
   1640       1.1  christos 	}
   1641       1.1  christos 	case EVBUFFER_EOL_CRLF: {
   1642       1.1  christos 		ev_ssize_t start_pos = it.pos;
   1643       1.1  christos 		/* Look for a LF ... */
   1644       1.1  christos 		if (evbuffer_strchr(&it, '\n') < 0)
   1645       1.1  christos 			goto done;
   1646       1.1  christos 		extra_drain = 1;
   1647       1.1  christos 		/* ... optionally preceeded by a CR. */
   1648       1.1  christos 		if (it.pos == start_pos)
   1649       1.1  christos 			break; /* If the first character is \n, don't back up */
   1650       1.1  christos 		/* This potentially does an extra linear walk over the first
   1651       1.1  christos 		 * few chains.  Probably, that's not too expensive unless you
   1652       1.1  christos 		 * have a really pathological setup. */
   1653       1.1  christos 		memcpy(&it2, &it, sizeof(it));
   1654       1.1  christos 		if (evbuffer_ptr_subtract(buffer, &it2, 1)<0)
   1655       1.1  christos 			break;
   1656       1.1  christos 		if (evbuffer_getchr(&it2) == '\r') {
   1657       1.1  christos 			memcpy(&it, &it2, sizeof(it));
   1658       1.1  christos 			extra_drain = 2;
   1659       1.1  christos 		}
   1660       1.1  christos 		break;
   1661       1.1  christos 	}
   1662       1.1  christos 	case EVBUFFER_EOL_LF:
   1663       1.1  christos 		if (evbuffer_strchr(&it, '\n') < 0)
   1664       1.1  christos 			goto done;
   1665       1.1  christos 		extra_drain = 1;
   1666       1.1  christos 		break;
   1667       1.1  christos 	case EVBUFFER_EOL_NUL:
   1668       1.1  christos 		if (evbuffer_strchr(&it, '\0') < 0)
   1669       1.1  christos 			goto done;
   1670       1.1  christos 		extra_drain = 1;
   1671       1.1  christos 		break;
   1672       1.1  christos 	default:
   1673       1.1  christos 		goto done;
   1674       1.1  christos 	}
   1675       1.1  christos 
   1676       1.1  christos 	ok = 1;
   1677       1.1  christos done:
   1678       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   1679       1.1  christos 
   1680       1.1  christos 	if (!ok)
   1681       1.1  christos 		PTR_NOT_FOUND(&it);
   1682       1.1  christos 	if (eol_len_out)
   1683       1.1  christos 		*eol_len_out = extra_drain;
   1684       1.1  christos 
   1685       1.1  christos 	return it;
   1686       1.1  christos }
   1687       1.1  christos 
   1688       1.1  christos char *
   1689       1.1  christos evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
   1690       1.1  christos 		enum evbuffer_eol_style eol_style)
   1691       1.1  christos {
   1692       1.1  christos 	struct evbuffer_ptr it;
   1693       1.1  christos 	char *line;
   1694       1.1  christos 	size_t n_to_copy=0, extra_drain=0;
   1695       1.1  christos 	char *result = NULL;
   1696       1.1  christos 
   1697       1.1  christos 	EVBUFFER_LOCK(buffer);
   1698       1.1  christos 
   1699       1.1  christos 	if (buffer->freeze_start) {
   1700       1.1  christos 		goto done;
   1701       1.1  christos 	}
   1702       1.1  christos 
   1703       1.1  christos 	it = evbuffer_search_eol(buffer, NULL, &extra_drain, eol_style);
   1704       1.1  christos 	if (it.pos < 0)
   1705       1.1  christos 		goto done;
   1706       1.1  christos 	n_to_copy = it.pos;
   1707       1.1  christos 
   1708       1.1  christos 	if ((line = mm_malloc(n_to_copy+1)) == NULL) {
   1709       1.1  christos 		event_warn("%s: out of memory", __func__);
   1710       1.1  christos 		goto done;
   1711       1.1  christos 	}
   1712       1.1  christos 
   1713       1.1  christos 	evbuffer_remove(buffer, line, n_to_copy);
   1714       1.1  christos 	line[n_to_copy] = '\0';
   1715       1.1  christos 
   1716       1.1  christos 	evbuffer_drain(buffer, extra_drain);
   1717       1.1  christos 	result = line;
   1718       1.1  christos done:
   1719       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   1720       1.1  christos 
   1721       1.1  christos 	if (n_read_out)
   1722       1.1  christos 		*n_read_out = result ? n_to_copy : 0;
   1723       1.1  christos 
   1724       1.1  christos 	return result;
   1725       1.1  christos }
   1726       1.1  christos 
   1727       1.1  christos #define EVBUFFER_CHAIN_MAX_AUTO_SIZE 4096
   1728       1.1  christos 
   1729       1.1  christos /* Adds data to an event buffer */
   1730       1.1  christos 
   1731       1.1  christos int
   1732       1.1  christos evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
   1733       1.1  christos {
   1734       1.1  christos 	struct evbuffer_chain *chain, *tmp;
   1735       1.1  christos 	const unsigned char *data = data_in;
   1736       1.1  christos 	size_t remain, to_alloc;
   1737       1.1  christos 	int result = -1;
   1738       1.1  christos 
   1739       1.1  christos 	EVBUFFER_LOCK(buf);
   1740       1.1  christos 
   1741       1.1  christos 	if (buf->freeze_end) {
   1742       1.1  christos 		goto done;
   1743       1.1  christos 	}
   1744   1.1.1.3  christos 	/* Prevent buf->total_len overflow */
   1745   1.1.1.3  christos 	if (datlen > EV_SIZE_MAX - buf->total_len) {
   1746   1.1.1.3  christos 		goto done;
   1747   1.1.1.3  christos 	}
   1748       1.1  christos 
   1749  1.1.1.10  christos 	if (*buf->last_with_datap == NULL) {
   1750  1.1.1.10  christos 		chain = buf->last;
   1751  1.1.1.10  christos 	} else {
   1752  1.1.1.10  christos 		chain = *buf->last_with_datap;
   1753  1.1.1.10  christos 	}
   1754       1.1  christos 
   1755       1.1  christos 	/* If there are no chains allocated for this buffer, allocate one
   1756       1.1  christos 	 * big enough to hold all the data. */
   1757       1.1  christos 	if (chain == NULL) {
   1758       1.1  christos 		chain = evbuffer_chain_new(datlen);
   1759       1.1  christos 		if (!chain)
   1760       1.1  christos 			goto done;
   1761       1.1  christos 		evbuffer_chain_insert(buf, chain);
   1762       1.1  christos 	}
   1763       1.1  christos 
   1764       1.1  christos 	if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
   1765   1.1.1.3  christos 		/* Always true for mutable buffers */
   1766   1.1.1.3  christos 		EVUTIL_ASSERT(chain->misalign >= 0 &&
   1767   1.1.1.3  christos 		    (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
   1768   1.1.1.3  christos 		remain = chain->buffer_len - (size_t)chain->misalign - chain->off;
   1769       1.1  christos 		if (remain >= datlen) {
   1770       1.1  christos 			/* there's enough space to hold all the data in the
   1771       1.1  christos 			 * current last chain */
   1772       1.1  christos 			memcpy(chain->buffer + chain->misalign + chain->off,
   1773       1.1  christos 			    data, datlen);
   1774       1.1  christos 			chain->off += datlen;
   1775       1.1  christos 			buf->total_len += datlen;
   1776       1.1  christos 			buf->n_add_for_cb += datlen;
   1777       1.1  christos 			goto out;
   1778       1.1  christos 		} else if (!CHAIN_PINNED(chain) &&
   1779       1.1  christos 		    evbuffer_chain_should_realign(chain, datlen)) {
   1780       1.1  christos 			/* we can fit the data into the misalignment */
   1781       1.1  christos 			evbuffer_chain_align(chain);
   1782       1.1  christos 
   1783       1.1  christos 			memcpy(chain->buffer + chain->off, data, datlen);
   1784       1.1  christos 			chain->off += datlen;
   1785       1.1  christos 			buf->total_len += datlen;
   1786       1.1  christos 			buf->n_add_for_cb += datlen;
   1787       1.1  christos 			goto out;
   1788       1.1  christos 		}
   1789       1.1  christos 	} else {
   1790       1.1  christos 		/* we cannot write any data to the last chain */
   1791       1.1  christos 		remain = 0;
   1792       1.1  christos 	}
   1793       1.1  christos 
   1794       1.1  christos 	/* we need to add another chain */
   1795       1.1  christos 	to_alloc = chain->buffer_len;
   1796       1.1  christos 	if (to_alloc <= EVBUFFER_CHAIN_MAX_AUTO_SIZE/2)
   1797       1.1  christos 		to_alloc <<= 1;
   1798       1.1  christos 	if (datlen > to_alloc)
   1799       1.1  christos 		to_alloc = datlen;
   1800       1.1  christos 	tmp = evbuffer_chain_new(to_alloc);
   1801       1.1  christos 	if (tmp == NULL)
   1802       1.1  christos 		goto done;
   1803       1.1  christos 
   1804       1.1  christos 	if (remain) {
   1805       1.1  christos 		memcpy(chain->buffer + chain->misalign + chain->off,
   1806       1.1  christos 		    data, remain);
   1807       1.1  christos 		chain->off += remain;
   1808       1.1  christos 		buf->total_len += remain;
   1809       1.1  christos 		buf->n_add_for_cb += remain;
   1810       1.1  christos 	}
   1811       1.1  christos 
   1812       1.1  christos 	data += remain;
   1813       1.1  christos 	datlen -= remain;
   1814       1.1  christos 
   1815       1.1  christos 	memcpy(tmp->buffer, data, datlen);
   1816       1.1  christos 	tmp->off = datlen;
   1817       1.1  christos 	evbuffer_chain_insert(buf, tmp);
   1818       1.1  christos 	buf->n_add_for_cb += datlen;
   1819       1.1  christos 
   1820       1.1  christos out:
   1821       1.1  christos 	evbuffer_invoke_callbacks_(buf);
   1822       1.1  christos 	result = 0;
   1823       1.1  christos done:
   1824       1.1  christos 	EVBUFFER_UNLOCK(buf);
   1825       1.1  christos 	return result;
   1826       1.1  christos }
   1827       1.1  christos 
   1828       1.1  christos int
   1829       1.1  christos evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
   1830       1.1  christos {
   1831       1.1  christos 	struct evbuffer_chain *chain, *tmp;
   1832       1.1  christos 	int result = -1;
   1833       1.1  christos 
   1834       1.1  christos 	EVBUFFER_LOCK(buf);
   1835       1.1  christos 
   1836  1.1.1.10  christos 	if (datlen == 0) {
   1837  1.1.1.10  christos 		result = 0;
   1838  1.1.1.10  christos 		goto done;
   1839  1.1.1.10  christos 	}
   1840       1.1  christos 	if (buf->freeze_start) {
   1841       1.1  christos 		goto done;
   1842       1.1  christos 	}
   1843   1.1.1.3  christos 	if (datlen > EV_SIZE_MAX - buf->total_len) {
   1844   1.1.1.3  christos 		goto done;
   1845   1.1.1.3  christos 	}
   1846       1.1  christos 
   1847       1.1  christos 	chain = buf->first;
   1848       1.1  christos 
   1849       1.1  christos 	if (chain == NULL) {
   1850       1.1  christos 		chain = evbuffer_chain_new(datlen);
   1851       1.1  christos 		if (!chain)
   1852       1.1  christos 			goto done;
   1853       1.1  christos 		evbuffer_chain_insert(buf, chain);
   1854       1.1  christos 	}
   1855       1.1  christos 
   1856       1.1  christos 	/* we cannot touch immutable buffers */
   1857       1.1  christos 	if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
   1858   1.1.1.3  christos 		/* Always true for mutable buffers */
   1859   1.1.1.3  christos 		EVUTIL_ASSERT(chain->misalign >= 0 &&
   1860   1.1.1.3  christos 		    (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
   1861   1.1.1.3  christos 
   1862       1.1  christos 		/* If this chain is empty, we can treat it as
   1863       1.1  christos 		 * 'empty at the beginning' rather than 'empty at the end' */
   1864       1.1  christos 		if (chain->off == 0)
   1865       1.1  christos 			chain->misalign = chain->buffer_len;
   1866       1.1  christos 
   1867       1.1  christos 		if ((size_t)chain->misalign >= datlen) {
   1868       1.1  christos 			/* we have enough space to fit everything */
   1869       1.1  christos 			memcpy(chain->buffer + chain->misalign - datlen,
   1870       1.1  christos 			    data, datlen);
   1871       1.1  christos 			chain->off += datlen;
   1872       1.1  christos 			chain->misalign -= datlen;
   1873       1.1  christos 			buf->total_len += datlen;
   1874       1.1  christos 			buf->n_add_for_cb += datlen;
   1875       1.1  christos 			goto out;
   1876       1.1  christos 		} else if (chain->misalign) {
   1877       1.1  christos 			/* we can only fit some of the data. */
   1878       1.1  christos 			memcpy(chain->buffer,
   1879       1.1  christos 			    (char*)data + datlen - chain->misalign,
   1880       1.1  christos 			    (size_t)chain->misalign);
   1881       1.1  christos 			chain->off += (size_t)chain->misalign;
   1882       1.1  christos 			buf->total_len += (size_t)chain->misalign;
   1883       1.1  christos 			buf->n_add_for_cb += (size_t)chain->misalign;
   1884       1.1  christos 			datlen -= (size_t)chain->misalign;
   1885       1.1  christos 			chain->misalign = 0;
   1886       1.1  christos 		}
   1887       1.1  christos 	}
   1888       1.1  christos 
   1889       1.1  christos 	/* we need to add another chain */
   1890       1.1  christos 	if ((tmp = evbuffer_chain_new(datlen)) == NULL)
   1891       1.1  christos 		goto done;
   1892       1.1  christos 	buf->first = tmp;
   1893  1.1.1.10  christos 	if (buf->last_with_datap == &buf->first && chain->off)
   1894       1.1  christos 		buf->last_with_datap = &tmp->next;
   1895       1.1  christos 
   1896       1.1  christos 	tmp->next = chain;
   1897       1.1  christos 
   1898       1.1  christos 	tmp->off = datlen;
   1899   1.1.1.3  christos 	EVUTIL_ASSERT(datlen <= tmp->buffer_len);
   1900       1.1  christos 	tmp->misalign = tmp->buffer_len - datlen;
   1901       1.1  christos 
   1902       1.1  christos 	memcpy(tmp->buffer + tmp->misalign, data, datlen);
   1903       1.1  christos 	buf->total_len += datlen;
   1904  1.1.1.10  christos 	buf->n_add_for_cb += datlen;
   1905       1.1  christos 
   1906       1.1  christos out:
   1907       1.1  christos 	evbuffer_invoke_callbacks_(buf);
   1908       1.1  christos 	result = 0;
   1909       1.1  christos done:
   1910       1.1  christos 	EVBUFFER_UNLOCK(buf);
   1911       1.1  christos 	return result;
   1912       1.1  christos }
   1913       1.1  christos 
   1914       1.1  christos /** Helper: realigns the memory in chain->buffer so that misalign is 0. */
   1915       1.1  christos static void
   1916       1.1  christos evbuffer_chain_align(struct evbuffer_chain *chain)
   1917       1.1  christos {
   1918       1.1  christos 	EVUTIL_ASSERT(!(chain->flags & EVBUFFER_IMMUTABLE));
   1919       1.1  christos 	EVUTIL_ASSERT(!(chain->flags & EVBUFFER_MEM_PINNED_ANY));
   1920       1.1  christos 	memmove(chain->buffer, chain->buffer + chain->misalign, chain->off);
   1921       1.1  christos 	chain->misalign = 0;
   1922       1.1  christos }
   1923       1.1  christos 
   1924       1.1  christos #define MAX_TO_COPY_IN_EXPAND 4096
   1925       1.1  christos #define MAX_TO_REALIGN_IN_EXPAND 2048
   1926       1.1  christos 
   1927       1.1  christos /** Helper: return true iff we should realign chain to fit datalen bytes of
   1928       1.1  christos     data in it. */
   1929       1.1  christos static int
   1930       1.1  christos evbuffer_chain_should_realign(struct evbuffer_chain *chain,
   1931       1.1  christos     size_t datlen)
   1932       1.1  christos {
   1933       1.1  christos 	return chain->buffer_len - chain->off >= datlen &&
   1934       1.1  christos 	    (chain->off < chain->buffer_len / 2) &&
   1935       1.1  christos 	    (chain->off <= MAX_TO_REALIGN_IN_EXPAND);
   1936       1.1  christos }
   1937       1.1  christos 
   1938       1.1  christos /* Expands the available space in the event buffer to at least datlen, all in
   1939       1.1  christos  * a single chunk.  Return that chunk. */
   1940       1.1  christos static struct evbuffer_chain *
   1941       1.1  christos evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
   1942       1.1  christos {
   1943       1.1  christos 	struct evbuffer_chain *chain, **chainp;
   1944       1.1  christos 	struct evbuffer_chain *result = NULL;
   1945       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buf);
   1946       1.1  christos 
   1947       1.1  christos 	chainp = buf->last_with_datap;
   1948       1.1  christos 
   1949       1.1  christos 	/* XXX If *chainp is no longer writeable, but has enough space in its
   1950       1.1  christos 	 * misalign, this might be a bad idea: we could still use *chainp, not
   1951       1.1  christos 	 * (*chainp)->next. */
   1952       1.1  christos 	if (*chainp && CHAIN_SPACE_LEN(*chainp) == 0)
   1953       1.1  christos 		chainp = &(*chainp)->next;
   1954       1.1  christos 
   1955       1.1  christos 	/* 'chain' now points to the first chain with writable space (if any)
   1956       1.1  christos 	 * We will either use it, realign it, replace it, or resize it. */
   1957       1.1  christos 	chain = *chainp;
   1958       1.1  christos 
   1959       1.1  christos 	if (chain == NULL ||
   1960       1.1  christos 	    (chain->flags & (EVBUFFER_IMMUTABLE|EVBUFFER_MEM_PINNED_ANY))) {
   1961       1.1  christos 		/* We can't use the last_with_data chain at all.  Just add a
   1962       1.1  christos 		 * new one that's big enough. */
   1963       1.1  christos 		goto insert_new;
   1964       1.1  christos 	}
   1965       1.1  christos 
   1966       1.1  christos 	/* If we can fit all the data, then we don't have to do anything */
   1967       1.1  christos 	if (CHAIN_SPACE_LEN(chain) >= datlen) {
   1968       1.1  christos 		result = chain;
   1969       1.1  christos 		goto ok;
   1970       1.1  christos 	}
   1971       1.1  christos 
   1972       1.1  christos 	/* If the chain is completely empty, just replace it by adding a new
   1973       1.1  christos 	 * empty chain. */
   1974       1.1  christos 	if (chain->off == 0) {
   1975       1.1  christos 		goto insert_new;
   1976       1.1  christos 	}
   1977       1.1  christos 
   1978       1.1  christos 	/* If the misalignment plus the remaining space fulfills our data
   1979       1.1  christos 	 * needs, we could just force an alignment to happen.  Afterwards, we
   1980       1.1  christos 	 * have enough space.  But only do this if we're saving a lot of space
   1981       1.1  christos 	 * and not moving too much data.  Otherwise the space savings are
   1982       1.1  christos 	 * probably offset by the time lost in copying.
   1983       1.1  christos 	 */
   1984       1.1  christos 	if (evbuffer_chain_should_realign(chain, datlen)) {
   1985       1.1  christos 		evbuffer_chain_align(chain);
   1986       1.1  christos 		result = chain;
   1987       1.1  christos 		goto ok;
   1988       1.1  christos 	}
   1989       1.1  christos 
   1990       1.1  christos 	/* At this point, we can either resize the last chunk with space in
   1991       1.1  christos 	 * it, use the next chunk after it, or   If we add a new chunk, we waste
   1992       1.1  christos 	 * CHAIN_SPACE_LEN(chain) bytes in the former last chunk.  If we
   1993       1.1  christos 	 * resize, we have to copy chain->off bytes.
   1994       1.1  christos 	 */
   1995       1.1  christos 
   1996       1.1  christos 	/* Would expanding this chunk be affordable and worthwhile? */
   1997       1.1  christos 	if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
   1998   1.1.1.3  christos 	    chain->off > MAX_TO_COPY_IN_EXPAND ||
   1999  1.1.1.10  christos 		datlen >= (EVBUFFER_CHAIN_MAX - chain->off)) {
   2000       1.1  christos 		/* It's not worth resizing this chain. Can the next one be
   2001       1.1  christos 		 * used? */
   2002       1.1  christos 		if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
   2003       1.1  christos 			/* Yes, we can just use the next chain (which should
   2004       1.1  christos 			 * be empty. */
   2005       1.1  christos 			result = chain->next;
   2006       1.1  christos 			goto ok;
   2007       1.1  christos 		} else {
   2008       1.1  christos 			/* No; append a new chain (which will free all
   2009       1.1  christos 			 * terminal empty chains.) */
   2010       1.1  christos 			goto insert_new;
   2011       1.1  christos 		}
   2012       1.1  christos 	} else {
   2013       1.1  christos 		/* Okay, we're going to try to resize this chain: Not doing so
   2014       1.1  christos 		 * would waste at least 1/8 of its current allocation, and we
   2015       1.1  christos 		 * can do so without having to copy more than
   2016       1.1  christos 		 * MAX_TO_COPY_IN_EXPAND bytes. */
   2017       1.1  christos 		/* figure out how much space we need */
   2018       1.1  christos 		size_t length = chain->off + datlen;
   2019       1.1  christos 		struct evbuffer_chain *tmp = evbuffer_chain_new(length);
   2020       1.1  christos 		if (tmp == NULL)
   2021       1.1  christos 			goto err;
   2022       1.1  christos 
   2023       1.1  christos 		/* copy the data over that we had so far */
   2024       1.1  christos 		tmp->off = chain->off;
   2025       1.1  christos 		memcpy(tmp->buffer, chain->buffer + chain->misalign,
   2026       1.1  christos 		    chain->off);
   2027       1.1  christos 		/* fix up the list */
   2028       1.1  christos 		EVUTIL_ASSERT(*chainp == chain);
   2029       1.1  christos 		result = *chainp = tmp;
   2030       1.1  christos 
   2031       1.1  christos 		if (buf->last == chain)
   2032       1.1  christos 			buf->last = tmp;
   2033       1.1  christos 
   2034       1.1  christos 		tmp->next = chain->next;
   2035       1.1  christos 		evbuffer_chain_free(chain);
   2036       1.1  christos 		goto ok;
   2037       1.1  christos 	}
   2038       1.1  christos 
   2039       1.1  christos insert_new:
   2040       1.1  christos 	result = evbuffer_chain_insert_new(buf, datlen);
   2041       1.1  christos 	if (!result)
   2042       1.1  christos 		goto err;
   2043       1.1  christos ok:
   2044       1.1  christos 	EVUTIL_ASSERT(result);
   2045       1.1  christos 	EVUTIL_ASSERT(CHAIN_SPACE_LEN(result) >= datlen);
   2046       1.1  christos err:
   2047       1.1  christos 	return result;
   2048       1.1  christos }
   2049       1.1  christos 
   2050       1.1  christos /* Make sure that datlen bytes are available for writing in the last n
   2051       1.1  christos  * chains.  Never copies or moves data. */
   2052       1.1  christos int
   2053       1.1  christos evbuffer_expand_fast_(struct evbuffer *buf, size_t datlen, int n)
   2054       1.1  christos {
   2055       1.1  christos 	struct evbuffer_chain *chain = buf->last, *tmp, *next;
   2056       1.1  christos 	size_t avail;
   2057       1.1  christos 	int used;
   2058       1.1  christos 
   2059       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buf);
   2060       1.1  christos 	EVUTIL_ASSERT(n >= 2);
   2061       1.1  christos 
   2062       1.1  christos 	if (chain == NULL || (chain->flags & EVBUFFER_IMMUTABLE)) {
   2063       1.1  christos 		/* There is no last chunk, or we can't touch the last chunk.
   2064       1.1  christos 		 * Just add a new chunk. */
   2065       1.1  christos 		chain = evbuffer_chain_new(datlen);
   2066       1.1  christos 		if (chain == NULL)
   2067       1.1  christos 			return (-1);
   2068       1.1  christos 
   2069       1.1  christos 		evbuffer_chain_insert(buf, chain);
   2070       1.1  christos 		return (0);
   2071       1.1  christos 	}
   2072       1.1  christos 
   2073       1.1  christos 	used = 0; /* number of chains we're using space in. */
   2074       1.1  christos 	avail = 0; /* how much space they have. */
   2075       1.1  christos 	/* How many bytes can we stick at the end of buffer as it is?  Iterate
   2076       1.1  christos 	 * over the chains at the end of the buffer, tring to see how much
   2077       1.1  christos 	 * space we have in the first n. */
   2078       1.1  christos 	for (chain = *buf->last_with_datap; chain; chain = chain->next) {
   2079       1.1  christos 		if (chain->off) {
   2080       1.1  christos 			size_t space = (size_t) CHAIN_SPACE_LEN(chain);
   2081       1.1  christos 			EVUTIL_ASSERT(chain == *buf->last_with_datap);
   2082       1.1  christos 			if (space) {
   2083       1.1  christos 				avail += space;
   2084       1.1  christos 				++used;
   2085       1.1  christos 			}
   2086       1.1  christos 		} else {
   2087       1.1  christos 			/* No data in chain; realign it. */
   2088       1.1  christos 			chain->misalign = 0;
   2089       1.1  christos 			avail += chain->buffer_len;
   2090       1.1  christos 			++used;
   2091       1.1  christos 		}
   2092       1.1  christos 		if (avail >= datlen) {
   2093       1.1  christos 			/* There is already enough space.  Just return */
   2094       1.1  christos 			return (0);
   2095       1.1  christos 		}
   2096       1.1  christos 		if (used == n)
   2097       1.1  christos 			break;
   2098       1.1  christos 	}
   2099       1.1  christos 
   2100       1.1  christos 	/* There wasn't enough space in the first n chains with space in
   2101       1.1  christos 	 * them. Either add a new chain with enough space, or replace all
   2102       1.1  christos 	 * empty chains with one that has enough space, depending on n. */
   2103       1.1  christos 	if (used < n) {
   2104       1.1  christos 		/* The loop ran off the end of the chains before it hit n
   2105       1.1  christos 		 * chains; we can add another. */
   2106       1.1  christos 		EVUTIL_ASSERT(chain == NULL);
   2107       1.1  christos 
   2108       1.1  christos 		tmp = evbuffer_chain_new(datlen - avail);
   2109       1.1  christos 		if (tmp == NULL)
   2110       1.1  christos 			return (-1);
   2111       1.1  christos 
   2112       1.1  christos 		buf->last->next = tmp;
   2113       1.1  christos 		buf->last = tmp;
   2114       1.1  christos 		/* (we would only set last_with_data if we added the first
   2115       1.1  christos 		 * chain. But if the buffer had no chains, we would have
   2116       1.1  christos 		 * just allocated a new chain earlier) */
   2117       1.1  christos 		return (0);
   2118       1.1  christos 	} else {
   2119       1.1  christos 		/* Nuke _all_ the empty chains. */
   2120       1.1  christos 		int rmv_all = 0; /* True iff we removed last_with_data. */
   2121       1.1  christos 		chain = *buf->last_with_datap;
   2122       1.1  christos 		if (!chain->off) {
   2123       1.1  christos 			EVUTIL_ASSERT(chain == buf->first);
   2124       1.1  christos 			rmv_all = 1;
   2125       1.1  christos 			avail = 0;
   2126       1.1  christos 		} else {
   2127   1.1.1.3  christos 			/* can't overflow, since only mutable chains have
   2128   1.1.1.3  christos 			 * huge misaligns. */
   2129       1.1  christos 			avail = (size_t) CHAIN_SPACE_LEN(chain);
   2130       1.1  christos 			chain = chain->next;
   2131       1.1  christos 		}
   2132       1.1  christos 
   2133       1.1  christos 
   2134       1.1  christos 		for (; chain; chain = next) {
   2135       1.1  christos 			next = chain->next;
   2136       1.1  christos 			EVUTIL_ASSERT(chain->off == 0);
   2137       1.1  christos 			evbuffer_chain_free(chain);
   2138       1.1  christos 		}
   2139   1.1.1.3  christos 		EVUTIL_ASSERT(datlen >= avail);
   2140       1.1  christos 		tmp = evbuffer_chain_new(datlen - avail);
   2141       1.1  christos 		if (tmp == NULL) {
   2142       1.1  christos 			if (rmv_all) {
   2143       1.1  christos 				ZERO_CHAIN(buf);
   2144       1.1  christos 			} else {
   2145       1.1  christos 				buf->last = *buf->last_with_datap;
   2146       1.1  christos 				(*buf->last_with_datap)->next = NULL;
   2147       1.1  christos 			}
   2148       1.1  christos 			return (-1);
   2149       1.1  christos 		}
   2150       1.1  christos 
   2151       1.1  christos 		if (rmv_all) {
   2152       1.1  christos 			buf->first = buf->last = tmp;
   2153       1.1  christos 			buf->last_with_datap = &buf->first;
   2154       1.1  christos 		} else {
   2155       1.1  christos 			(*buf->last_with_datap)->next = tmp;
   2156       1.1  christos 			buf->last = tmp;
   2157       1.1  christos 		}
   2158       1.1  christos 		return (0);
   2159       1.1  christos 	}
   2160       1.1  christos }
   2161       1.1  christos 
   2162       1.1  christos int
   2163       1.1  christos evbuffer_expand(struct evbuffer *buf, size_t datlen)
   2164       1.1  christos {
   2165       1.1  christos 	struct evbuffer_chain *chain;
   2166       1.1  christos 
   2167       1.1  christos 	EVBUFFER_LOCK(buf);
   2168       1.1  christos 	chain = evbuffer_expand_singlechain(buf, datlen);
   2169       1.1  christos 	EVBUFFER_UNLOCK(buf);
   2170       1.1  christos 	return chain ? 0 : -1;
   2171       1.1  christos }
   2172       1.1  christos 
   2173       1.1  christos /*
   2174       1.1  christos  * Reads data from a file descriptor into a buffer.
   2175       1.1  christos  */
   2176       1.1  christos 
   2177       1.1  christos #if defined(EVENT__HAVE_SYS_UIO_H) || defined(_WIN32)
   2178       1.1  christos #define USE_IOVEC_IMPL
   2179       1.1  christos #endif
   2180       1.1  christos 
   2181       1.1  christos #ifdef USE_IOVEC_IMPL
   2182       1.1  christos 
   2183       1.1  christos #ifdef EVENT__HAVE_SYS_UIO_H
   2184       1.1  christos /* number of iovec we use for writev, fragmentation is going to determine
   2185       1.1  christos  * how much we end up writing */
   2186       1.1  christos 
   2187       1.1  christos #define DEFAULT_WRITE_IOVEC 128
   2188       1.1  christos 
   2189       1.1  christos #if defined(UIO_MAXIOV) && UIO_MAXIOV < DEFAULT_WRITE_IOVEC
   2190       1.1  christos #define NUM_WRITE_IOVEC UIO_MAXIOV
   2191       1.1  christos #elif defined(IOV_MAX) && IOV_MAX < DEFAULT_WRITE_IOVEC
   2192       1.1  christos #define NUM_WRITE_IOVEC IOV_MAX
   2193       1.1  christos #else
   2194       1.1  christos #define NUM_WRITE_IOVEC DEFAULT_WRITE_IOVEC
   2195       1.1  christos #endif
   2196       1.1  christos 
   2197       1.1  christos #define IOV_TYPE struct iovec
   2198       1.1  christos #define IOV_PTR_FIELD iov_base
   2199       1.1  christos #define IOV_LEN_FIELD iov_len
   2200       1.1  christos #define IOV_LEN_TYPE size_t
   2201       1.1  christos #else
   2202       1.1  christos #define NUM_WRITE_IOVEC 16
   2203       1.1  christos #define IOV_TYPE WSABUF
   2204       1.1  christos #define IOV_PTR_FIELD buf
   2205       1.1  christos #define IOV_LEN_FIELD len
   2206       1.1  christos #define IOV_LEN_TYPE unsigned long
   2207       1.1  christos #endif
   2208       1.1  christos #endif
   2209       1.1  christos #define NUM_READ_IOVEC 4
   2210       1.1  christos 
   2211       1.1  christos #define EVBUFFER_MAX_READ	4096
   2212       1.1  christos 
   2213       1.1  christos /** Helper function to figure out which space to use for reading data into
   2214       1.1  christos     an evbuffer.  Internal use only.
   2215       1.1  christos 
   2216       1.1  christos     @param buf The buffer to read into
   2217       1.1  christos     @param howmuch How much we want to read.
   2218       1.1  christos     @param vecs An array of two or more iovecs or WSABUFs.
   2219       1.1  christos     @param n_vecs_avail The length of vecs
   2220       1.1  christos     @param chainp A pointer to a variable to hold the first chain we're
   2221       1.1  christos       reading into.
   2222       1.1  christos     @param exact Boolean: if true, we do not provide more than 'howmuch'
   2223       1.1  christos       space in the vectors, even if more space is available.
   2224       1.1  christos     @return The number of buffers we're using.
   2225       1.1  christos  */
   2226       1.1  christos int
   2227       1.1  christos evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
   2228       1.1  christos     struct evbuffer_iovec *vecs, int n_vecs_avail,
   2229       1.1  christos     struct evbuffer_chain ***chainp, int exact)
   2230       1.1  christos {
   2231       1.1  christos 	struct evbuffer_chain *chain;
   2232       1.1  christos 	struct evbuffer_chain **firstchainp;
   2233       1.1  christos 	size_t so_far;
   2234       1.1  christos 	int i;
   2235       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buf);
   2236       1.1  christos 
   2237       1.1  christos 	if (howmuch < 0)
   2238       1.1  christos 		return -1;
   2239       1.1  christos 
   2240       1.1  christos 	so_far = 0;
   2241       1.1  christos 	/* Let firstchain be the first chain with any space on it */
   2242       1.1  christos 	firstchainp = buf->last_with_datap;
   2243  1.1.1.10  christos 	EVUTIL_ASSERT(*firstchainp);
   2244       1.1  christos 	if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
   2245       1.1  christos 		firstchainp = &(*firstchainp)->next;
   2246       1.1  christos 	}
   2247       1.1  christos 
   2248       1.1  christos 	chain = *firstchainp;
   2249  1.1.1.10  christos 	EVUTIL_ASSERT(chain);
   2250       1.1  christos 	for (i = 0; i < n_vecs_avail && so_far < (size_t)howmuch; ++i) {
   2251       1.1  christos 		size_t avail = (size_t) CHAIN_SPACE_LEN(chain);
   2252       1.1  christos 		if (avail > (howmuch - so_far) && exact)
   2253       1.1  christos 			avail = howmuch - so_far;
   2254  1.1.1.10  christos 		vecs[i].iov_base = (void *)CHAIN_SPACE_PTR(chain);
   2255       1.1  christos 		vecs[i].iov_len = avail;
   2256       1.1  christos 		so_far += avail;
   2257       1.1  christos 		chain = chain->next;
   2258       1.1  christos 	}
   2259       1.1  christos 
   2260       1.1  christos 	*chainp = firstchainp;
   2261       1.1  christos 	return i;
   2262       1.1  christos }
   2263       1.1  christos 
   2264       1.1  christos static int
   2265       1.1  christos get_n_bytes_readable_on_socket(evutil_socket_t fd)
   2266       1.1  christos {
   2267       1.1  christos #if defined(FIONREAD) && defined(_WIN32)
   2268       1.1  christos 	unsigned long lng = EVBUFFER_MAX_READ;
   2269       1.1  christos 	if (ioctlsocket(fd, FIONREAD, &lng) < 0)
   2270       1.1  christos 		return -1;
   2271   1.1.1.3  christos 	/* Can overflow, but mostly harmlessly. XXXX */
   2272       1.1  christos 	return (int)lng;
   2273       1.1  christos #elif defined(FIONREAD)
   2274       1.1  christos 	int n = EVBUFFER_MAX_READ;
   2275       1.1  christos 	if (ioctl(fd, FIONREAD, &n) < 0)
   2276       1.1  christos 		return -1;
   2277       1.1  christos 	return n;
   2278       1.1  christos #else
   2279       1.1  christos 	return EVBUFFER_MAX_READ;
   2280       1.1  christos #endif
   2281       1.1  christos }
   2282       1.1  christos 
   2283       1.1  christos /* TODO(niels): should this function return ev_ssize_t and take ev_ssize_t
   2284       1.1  christos  * as howmuch? */
   2285       1.1  christos int
   2286       1.1  christos evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
   2287       1.1  christos {
   2288       1.1  christos 	struct evbuffer_chain **chainp;
   2289       1.1  christos 	int n;
   2290       1.1  christos 	int result;
   2291       1.1  christos 
   2292       1.1  christos #ifdef USE_IOVEC_IMPL
   2293       1.1  christos 	int nvecs, i, remaining;
   2294       1.1  christos #else
   2295       1.1  christos 	struct evbuffer_chain *chain;
   2296       1.1  christos 	unsigned char *p;
   2297       1.1  christos #endif
   2298       1.1  christos 
   2299       1.1  christos 	EVBUFFER_LOCK(buf);
   2300       1.1  christos 
   2301       1.1  christos 	if (buf->freeze_end) {
   2302       1.1  christos 		result = -1;
   2303       1.1  christos 		goto done;
   2304       1.1  christos 	}
   2305       1.1  christos 
   2306       1.1  christos 	n = get_n_bytes_readable_on_socket(fd);
   2307       1.1  christos 	if (n <= 0 || n > EVBUFFER_MAX_READ)
   2308       1.1  christos 		n = EVBUFFER_MAX_READ;
   2309       1.1  christos 	if (howmuch < 0 || howmuch > n)
   2310       1.1  christos 		howmuch = n;
   2311       1.1  christos 
   2312       1.1  christos #ifdef USE_IOVEC_IMPL
   2313       1.1  christos 	/* Since we can use iovecs, we're willing to use the last
   2314       1.1  christos 	 * NUM_READ_IOVEC chains. */
   2315       1.1  christos 	if (evbuffer_expand_fast_(buf, howmuch, NUM_READ_IOVEC) == -1) {
   2316       1.1  christos 		result = -1;
   2317       1.1  christos 		goto done;
   2318       1.1  christos 	} else {
   2319       1.1  christos 		IOV_TYPE vecs[NUM_READ_IOVEC];
   2320       1.1  christos #ifdef EVBUFFER_IOVEC_IS_NATIVE_
   2321       1.1  christos 		nvecs = evbuffer_read_setup_vecs_(buf, howmuch, vecs,
   2322       1.1  christos 		    NUM_READ_IOVEC, &chainp, 1);
   2323       1.1  christos #else
   2324       1.1  christos 		/* We aren't using the native struct iovec.  Therefore,
   2325       1.1  christos 		   we are on win32. */
   2326       1.1  christos 		struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
   2327       1.1  christos 		nvecs = evbuffer_read_setup_vecs_(buf, howmuch, ev_vecs, 2,
   2328       1.1  christos 		    &chainp, 1);
   2329       1.1  christos 
   2330       1.1  christos 		for (i=0; i < nvecs; ++i)
   2331       1.1  christos 			WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
   2332       1.1  christos #endif
   2333       1.1  christos 
   2334       1.1  christos #ifdef _WIN32
   2335       1.1  christos 		{
   2336       1.1  christos 			DWORD bytesRead;
   2337       1.1  christos 			DWORD flags=0;
   2338       1.1  christos 			if (WSARecv(fd, vecs, nvecs, &bytesRead, &flags, NULL, NULL)) {
   2339       1.1  christos 				/* The read failed. It might be a close,
   2340       1.1  christos 				 * or it might be an error. */
   2341       1.1  christos 				if (WSAGetLastError() == WSAECONNABORTED)
   2342       1.1  christos 					n = 0;
   2343       1.1  christos 				else
   2344       1.1  christos 					n = -1;
   2345       1.1  christos 			} else
   2346       1.1  christos 				n = bytesRead;
   2347       1.1  christos 		}
   2348       1.1  christos #else
   2349       1.1  christos 		n = readv(fd, vecs, nvecs);
   2350       1.1  christos #endif
   2351       1.1  christos 	}
   2352       1.1  christos 
   2353       1.1  christos #else /*!USE_IOVEC_IMPL*/
   2354       1.1  christos 	/* If we don't have FIONREAD, we might waste some space here */
   2355       1.1  christos 	/* XXX we _will_ waste some space here if there is any space left
   2356       1.1  christos 	 * over on buf->last. */
   2357       1.1  christos 	if ((chain = evbuffer_expand_singlechain(buf, howmuch)) == NULL) {
   2358       1.1  christos 		result = -1;
   2359       1.1  christos 		goto done;
   2360       1.1  christos 	}
   2361       1.1  christos 
   2362       1.1  christos 	/* We can append new data at this point */
   2363       1.1  christos 	p = chain->buffer + chain->misalign + chain->off;
   2364       1.1  christos 
   2365       1.1  christos #ifndef _WIN32
   2366       1.1  christos 	n = read(fd, p, howmuch);
   2367       1.1  christos #else
   2368       1.1  christos 	n = recv(fd, p, howmuch, 0);
   2369       1.1  christos #endif
   2370       1.1  christos #endif /* USE_IOVEC_IMPL */
   2371       1.1  christos 
   2372       1.1  christos 	if (n == -1) {
   2373       1.1  christos 		result = -1;
   2374       1.1  christos 		goto done;
   2375       1.1  christos 	}
   2376       1.1  christos 	if (n == 0) {
   2377       1.1  christos 		result = 0;
   2378       1.1  christos 		goto done;
   2379       1.1  christos 	}
   2380       1.1  christos 
   2381       1.1  christos #ifdef USE_IOVEC_IMPL
   2382       1.1  christos 	remaining = n;
   2383       1.1  christos 	for (i=0; i < nvecs; ++i) {
   2384   1.1.1.3  christos 		/* can't overflow, since only mutable chains have
   2385   1.1.1.3  christos 		 * huge misaligns. */
   2386   1.1.1.3  christos 		size_t space = (size_t) CHAIN_SPACE_LEN(*chainp);
   2387   1.1.1.3  christos 		/* XXXX This is a kludge that can waste space in perverse
   2388   1.1.1.3  christos 		 * situations. */
   2389   1.1.1.3  christos 		if (space > EVBUFFER_CHAIN_MAX)
   2390   1.1.1.3  christos 			space = EVBUFFER_CHAIN_MAX;
   2391   1.1.1.3  christos 		if ((ev_ssize_t)space < remaining) {
   2392       1.1  christos 			(*chainp)->off += space;
   2393       1.1  christos 			remaining -= (int)space;
   2394       1.1  christos 		} else {
   2395       1.1  christos 			(*chainp)->off += remaining;
   2396       1.1  christos 			buf->last_with_datap = chainp;
   2397       1.1  christos 			break;
   2398       1.1  christos 		}
   2399       1.1  christos 		chainp = &(*chainp)->next;
   2400       1.1  christos 	}
   2401       1.1  christos #else
   2402       1.1  christos 	chain->off += n;
   2403       1.1  christos 	advance_last_with_data(buf);
   2404       1.1  christos #endif
   2405       1.1  christos 	buf->total_len += n;
   2406       1.1  christos 	buf->n_add_for_cb += n;
   2407       1.1  christos 
   2408       1.1  christos 	/* Tell someone about changes in this buffer */
   2409       1.1  christos 	evbuffer_invoke_callbacks_(buf);
   2410       1.1  christos 	result = n;
   2411       1.1  christos done:
   2412       1.1  christos 	EVBUFFER_UNLOCK(buf);
   2413       1.1  christos 	return result;
   2414       1.1  christos }
   2415       1.1  christos 
   2416       1.1  christos #ifdef USE_IOVEC_IMPL
   2417       1.1  christos static inline int
   2418       1.1  christos evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
   2419       1.1  christos     ev_ssize_t howmuch)
   2420       1.1  christos {
   2421       1.1  christos 	IOV_TYPE iov[NUM_WRITE_IOVEC];
   2422       1.1  christos 	struct evbuffer_chain *chain = buffer->first;
   2423       1.1  christos 	int n, i = 0;
   2424       1.1  christos 
   2425       1.1  christos 	if (howmuch < 0)
   2426       1.1  christos 		return -1;
   2427       1.1  christos 
   2428       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buffer);
   2429       1.1  christos 	/* XXX make this top out at some maximal data length?  if the
   2430       1.1  christos 	 * buffer has (say) 1MB in it, split over 128 chains, there's
   2431       1.1  christos 	 * no way it all gets written in one go. */
   2432       1.1  christos 	while (chain != NULL && i < NUM_WRITE_IOVEC && howmuch) {
   2433       1.1  christos #ifdef USE_SENDFILE
   2434       1.1  christos 		/* we cannot write the file info via writev */
   2435       1.1  christos 		if (chain->flags & EVBUFFER_SENDFILE)
   2436       1.1  christos 			break;
   2437       1.1  christos #endif
   2438       1.1  christos 		iov[i].IOV_PTR_FIELD = (void *) (chain->buffer + chain->misalign);
   2439       1.1  christos 		if ((size_t)howmuch >= chain->off) {
   2440       1.1  christos 			/* XXXcould be problematic when windows supports mmap*/
   2441       1.1  christos 			iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)chain->off;
   2442       1.1  christos 			howmuch -= chain->off;
   2443       1.1  christos 		} else {
   2444       1.1  christos 			/* XXXcould be problematic when windows supports mmap*/
   2445       1.1  christos 			iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)howmuch;
   2446       1.1  christos 			break;
   2447       1.1  christos 		}
   2448       1.1  christos 		chain = chain->next;
   2449       1.1  christos 	}
   2450       1.1  christos 	if (! i)
   2451       1.1  christos 		return 0;
   2452       1.1  christos 
   2453       1.1  christos #ifdef _WIN32
   2454       1.1  christos 	{
   2455       1.1  christos 		DWORD bytesSent;
   2456       1.1  christos 		if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
   2457       1.1  christos 			n = -1;
   2458       1.1  christos 		else
   2459       1.1  christos 			n = bytesSent;
   2460       1.1  christos 	}
   2461       1.1  christos #else
   2462       1.1  christos 	n = writev(fd, iov, i);
   2463       1.1  christos #endif
   2464       1.1  christos 	return (n);
   2465       1.1  christos }
   2466       1.1  christos #endif
   2467       1.1  christos 
   2468       1.1  christos #ifdef USE_SENDFILE
   2469       1.1  christos static inline int
   2470       1.1  christos evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
   2471       1.1  christos     ev_ssize_t howmuch)
   2472       1.1  christos {
   2473       1.1  christos 	struct evbuffer_chain *chain = buffer->first;
   2474       1.1  christos 	struct evbuffer_chain_file_segment *info =
   2475       1.1  christos 	    EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment,
   2476       1.1  christos 		chain);
   2477       1.1  christos 	const int source_fd = info->segment->fd;
   2478       1.1  christos #if defined(SENDFILE_IS_MACOSX) || defined(SENDFILE_IS_FREEBSD)
   2479       1.1  christos 	int res;
   2480       1.1  christos 	ev_off_t len = chain->off;
   2481       1.1  christos #elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
   2482       1.1  christos 	ev_ssize_t res;
   2483  1.1.1.10  christos 	off_t offset = chain->misalign;
   2484       1.1  christos #endif
   2485       1.1  christos 
   2486       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buffer);
   2487       1.1  christos 
   2488       1.1  christos #if defined(SENDFILE_IS_MACOSX)
   2489       1.1  christos 	res = sendfile(source_fd, dest_fd, chain->misalign, &len, NULL, 0);
   2490       1.1  christos 	if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
   2491       1.1  christos 		return (-1);
   2492       1.1  christos 
   2493       1.1  christos 	return (len);
   2494       1.1  christos #elif defined(SENDFILE_IS_FREEBSD)
   2495       1.1  christos 	res = sendfile(source_fd, dest_fd, chain->misalign, chain->off, NULL, &len, 0);
   2496       1.1  christos 	if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
   2497       1.1  christos 		return (-1);
   2498       1.1  christos 
   2499       1.1  christos 	return (len);
   2500       1.1  christos #elif defined(SENDFILE_IS_LINUX)
   2501       1.1  christos 	/* TODO(niels): implement splice */
   2502       1.1  christos 	res = sendfile(dest_fd, source_fd, &offset, chain->off);
   2503       1.1  christos 	if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
   2504       1.1  christos 		/* if this is EAGAIN or EINTR return 0; otherwise, -1 */
   2505       1.1  christos 		return (0);
   2506       1.1  christos 	}
   2507       1.1  christos 	return (res);
   2508       1.1  christos #elif defined(SENDFILE_IS_SOLARIS)
   2509       1.1  christos 	{
   2510       1.1  christos 		const off_t offset_orig = offset;
   2511       1.1  christos 		res = sendfile(dest_fd, source_fd, &offset, chain->off);
   2512       1.1  christos 		if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
   2513       1.1  christos 			if (offset - offset_orig)
   2514       1.1  christos 				return offset - offset_orig;
   2515       1.1  christos 			/* if this is EAGAIN or EINTR and no bytes were
   2516       1.1  christos 			 * written, return 0 */
   2517       1.1  christos 			return (0);
   2518       1.1  christos 		}
   2519       1.1  christos 		return (res);
   2520       1.1  christos 	}
   2521       1.1  christos #endif
   2522       1.1  christos }
   2523       1.1  christos #endif
   2524       1.1  christos 
   2525       1.1  christos int
   2526       1.1  christos evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
   2527       1.1  christos     ev_ssize_t howmuch)
   2528       1.1  christos {
   2529       1.1  christos 	int n = -1;
   2530       1.1  christos 
   2531       1.1  christos 	EVBUFFER_LOCK(buffer);
   2532       1.1  christos 
   2533       1.1  christos 	if (buffer->freeze_start) {
   2534       1.1  christos 		goto done;
   2535       1.1  christos 	}
   2536       1.1  christos 
   2537       1.1  christos 	if (howmuch < 0 || (size_t)howmuch > buffer->total_len)
   2538       1.1  christos 		howmuch = buffer->total_len;
   2539       1.1  christos 
   2540       1.1  christos 	if (howmuch > 0) {
   2541       1.1  christos #ifdef USE_SENDFILE
   2542       1.1  christos 		struct evbuffer_chain *chain = buffer->first;
   2543       1.1  christos 		if (chain != NULL && (chain->flags & EVBUFFER_SENDFILE))
   2544       1.1  christos 			n = evbuffer_write_sendfile(buffer, fd, howmuch);
   2545       1.1  christos 		else {
   2546       1.1  christos #endif
   2547       1.1  christos #ifdef USE_IOVEC_IMPL
   2548       1.1  christos 		n = evbuffer_write_iovec(buffer, fd, howmuch);
   2549       1.1  christos #elif defined(_WIN32)
   2550       1.1  christos 		/* XXX(nickm) Don't disable this code until we know if
   2551       1.1  christos 		 * the WSARecv code above works. */
   2552       1.1  christos 		void *p = evbuffer_pullup(buffer, howmuch);
   2553   1.1.1.3  christos 		EVUTIL_ASSERT(p || !howmuch);
   2554       1.1  christos 		n = send(fd, p, howmuch, 0);
   2555       1.1  christos #else
   2556       1.1  christos 		void *p = evbuffer_pullup(buffer, howmuch);
   2557   1.1.1.3  christos 		EVUTIL_ASSERT(p || !howmuch);
   2558       1.1  christos 		n = write(fd, p, howmuch);
   2559       1.1  christos #endif
   2560       1.1  christos #ifdef USE_SENDFILE
   2561       1.1  christos 		}
   2562       1.1  christos #endif
   2563       1.1  christos 	}
   2564       1.1  christos 
   2565       1.1  christos 	if (n > 0)
   2566       1.1  christos 		evbuffer_drain(buffer, n);
   2567       1.1  christos 
   2568       1.1  christos done:
   2569       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   2570       1.1  christos 	return (n);
   2571       1.1  christos }
   2572       1.1  christos 
   2573       1.1  christos int
   2574       1.1  christos evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd)
   2575       1.1  christos {
   2576       1.1  christos 	return evbuffer_write_atmost(buffer, fd, -1);
   2577       1.1  christos }
   2578       1.1  christos 
   2579       1.1  christos unsigned char *
   2580       1.1  christos evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len)
   2581       1.1  christos {
   2582       1.1  christos 	unsigned char *search;
   2583       1.1  christos 	struct evbuffer_ptr ptr;
   2584       1.1  christos 
   2585       1.1  christos 	EVBUFFER_LOCK(buffer);
   2586       1.1  christos 
   2587       1.1  christos 	ptr = evbuffer_search(buffer, (const char *)what, len, NULL);
   2588       1.1  christos 	if (ptr.pos < 0) {
   2589       1.1  christos 		search = NULL;
   2590       1.1  christos 	} else {
   2591       1.1  christos 		search = evbuffer_pullup(buffer, ptr.pos + len);
   2592       1.1  christos 		if (search)
   2593       1.1  christos 			search += ptr.pos;
   2594       1.1  christos 	}
   2595       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   2596       1.1  christos 	return search;
   2597       1.1  christos }
   2598       1.1  christos 
   2599       1.1  christos /* Subract <b>howfar</b> from the position of <b>pos</b> within
   2600       1.1  christos  * <b>buf</b>. Returns 0 on success, -1 on failure.
   2601       1.1  christos  *
   2602       1.1  christos  * This isn't exposed yet, because of potential inefficiency issues.
   2603       1.1  christos  * Maybe it should be. */
   2604       1.1  christos static int
   2605       1.1  christos evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
   2606       1.1  christos     size_t howfar)
   2607       1.1  christos {
   2608   1.1.1.3  christos 	if (pos->pos < 0)
   2609   1.1.1.3  christos 		return -1;
   2610       1.1  christos 	if (howfar > (size_t)pos->pos)
   2611       1.1  christos 		return -1;
   2612       1.1  christos 	if (pos->internal_.chain && howfar <= pos->internal_.pos_in_chain) {
   2613       1.1  christos 		pos->internal_.pos_in_chain -= howfar;
   2614       1.1  christos 		pos->pos -= howfar;
   2615       1.1  christos 		return 0;
   2616       1.1  christos 	} else {
   2617       1.1  christos 		const size_t newpos = pos->pos - howfar;
   2618       1.1  christos 		/* Here's the inefficient part: it walks over the
   2619       1.1  christos 		 * chains until we hit newpos. */
   2620       1.1  christos 		return evbuffer_ptr_set(buf, pos, newpos, EVBUFFER_PTR_SET);
   2621       1.1  christos 	}
   2622       1.1  christos }
   2623       1.1  christos 
   2624       1.1  christos int
   2625       1.1  christos evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
   2626       1.1  christos     size_t position, enum evbuffer_ptr_how how)
   2627       1.1  christos {
   2628       1.1  christos 	size_t left = position;
   2629       1.1  christos 	struct evbuffer_chain *chain = NULL;
   2630       1.1  christos 	int result = 0;
   2631       1.1  christos 
   2632       1.1  christos 	EVBUFFER_LOCK(buf);
   2633       1.1  christos 
   2634       1.1  christos 	switch (how) {
   2635       1.1  christos 	case EVBUFFER_PTR_SET:
   2636       1.1  christos 		chain = buf->first;
   2637       1.1  christos 		pos->pos = position;
   2638       1.1  christos 		position = 0;
   2639       1.1  christos 		break;
   2640       1.1  christos 	case EVBUFFER_PTR_ADD:
   2641       1.1  christos 		/* this avoids iterating over all previous chains if
   2642       1.1  christos 		   we just want to advance the position */
   2643   1.1.1.3  christos 		if (pos->pos < 0 || EV_SIZE_MAX - position < (size_t)pos->pos) {
   2644   1.1.1.3  christos 			EVBUFFER_UNLOCK(buf);
   2645   1.1.1.3  christos 			return -1;
   2646   1.1.1.3  christos 		}
   2647       1.1  christos 		chain = pos->internal_.chain;
   2648       1.1  christos 		pos->pos += position;
   2649       1.1  christos 		position = pos->internal_.pos_in_chain;
   2650       1.1  christos 		break;
   2651       1.1  christos 	}
   2652       1.1  christos 
   2653   1.1.1.3  christos 	EVUTIL_ASSERT(EV_SIZE_MAX - left >= position);
   2654       1.1  christos 	while (chain && position + left >= chain->off) {
   2655       1.1  christos 		left -= chain->off - position;
   2656       1.1  christos 		chain = chain->next;
   2657       1.1  christos 		position = 0;
   2658       1.1  christos 	}
   2659       1.1  christos 	if (chain) {
   2660       1.1  christos 		pos->internal_.chain = chain;
   2661       1.1  christos 		pos->internal_.pos_in_chain = position + left;
   2662       1.1  christos 	} else if (left == 0) {
   2663       1.1  christos 		/* The first byte in the (nonexistent) chain after the last chain */
   2664       1.1  christos 		pos->internal_.chain = NULL;
   2665       1.1  christos 		pos->internal_.pos_in_chain = 0;
   2666       1.1  christos 	} else {
   2667       1.1  christos 		PTR_NOT_FOUND(pos);
   2668       1.1  christos 		result = -1;
   2669       1.1  christos 	}
   2670       1.1  christos 
   2671       1.1  christos 	EVBUFFER_UNLOCK(buf);
   2672       1.1  christos 
   2673       1.1  christos 	return result;
   2674       1.1  christos }
   2675       1.1  christos 
   2676       1.1  christos /**
   2677       1.1  christos    Compare the bytes in buf at position pos to the len bytes in mem.  Return
   2678       1.1  christos    less than 0, 0, or greater than 0 as memcmp.
   2679       1.1  christos  */
   2680       1.1  christos static int
   2681       1.1  christos evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
   2682       1.1  christos     const char *mem, size_t len)
   2683       1.1  christos {
   2684       1.1  christos 	struct evbuffer_chain *chain;
   2685       1.1  christos 	size_t position;
   2686       1.1  christos 	int r;
   2687       1.1  christos 
   2688       1.1  christos 	ASSERT_EVBUFFER_LOCKED(buf);
   2689       1.1  christos 
   2690   1.1.1.3  christos 	if (pos->pos < 0 ||
   2691   1.1.1.3  christos 	    EV_SIZE_MAX - len < (size_t)pos->pos ||
   2692   1.1.1.3  christos 	    pos->pos + len > buf->total_len)
   2693       1.1  christos 		return -1;
   2694       1.1  christos 
   2695       1.1  christos 	chain = pos->internal_.chain;
   2696       1.1  christos 	position = pos->internal_.pos_in_chain;
   2697       1.1  christos 	while (len && chain) {
   2698       1.1  christos 		size_t n_comparable;
   2699       1.1  christos 		if (len + position > chain->off)
   2700       1.1  christos 			n_comparable = chain->off - position;
   2701       1.1  christos 		else
   2702       1.1  christos 			n_comparable = len;
   2703       1.1  christos 		r = memcmp(chain->buffer + chain->misalign + position, mem,
   2704       1.1  christos 		    n_comparable);
   2705       1.1  christos 		if (r)
   2706       1.1  christos 			return r;
   2707       1.1  christos 		mem += n_comparable;
   2708       1.1  christos 		len -= n_comparable;
   2709       1.1  christos 		position = 0;
   2710       1.1  christos 		chain = chain->next;
   2711       1.1  christos 	}
   2712       1.1  christos 
   2713       1.1  christos 	return 0;
   2714       1.1  christos }
   2715       1.1  christos 
   2716       1.1  christos struct evbuffer_ptr
   2717       1.1  christos evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start)
   2718       1.1  christos {
   2719       1.1  christos 	return evbuffer_search_range(buffer, what, len, start, NULL);
   2720       1.1  christos }
   2721       1.1  christos 
   2722       1.1  christos struct evbuffer_ptr
   2723       1.1  christos evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end)
   2724       1.1  christos {
   2725       1.1  christos 	struct evbuffer_ptr pos;
   2726       1.1  christos 	struct evbuffer_chain *chain, *last_chain = NULL;
   2727       1.1  christos 	const unsigned char *p;
   2728       1.1  christos 	char first;
   2729       1.1  christos 
   2730       1.1  christos 	EVBUFFER_LOCK(buffer);
   2731       1.1  christos 
   2732       1.1  christos 	if (start) {
   2733       1.1  christos 		memcpy(&pos, start, sizeof(pos));
   2734       1.1  christos 		chain = pos.internal_.chain;
   2735       1.1  christos 	} else {
   2736       1.1  christos 		pos.pos = 0;
   2737       1.1  christos 		chain = pos.internal_.chain = buffer->first;
   2738       1.1  christos 		pos.internal_.pos_in_chain = 0;
   2739       1.1  christos 	}
   2740       1.1  christos 
   2741       1.1  christos 	if (end)
   2742       1.1  christos 		last_chain = end->internal_.chain;
   2743       1.1  christos 
   2744       1.1  christos 	if (!len || len > EV_SSIZE_MAX)
   2745       1.1  christos 		goto done;
   2746       1.1  christos 
   2747       1.1  christos 	first = what[0];
   2748       1.1  christos 
   2749       1.1  christos 	while (chain) {
   2750       1.1  christos 		const unsigned char *start_at =
   2751       1.1  christos 		    chain->buffer + chain->misalign +
   2752       1.1  christos 		    pos.internal_.pos_in_chain;
   2753       1.1  christos 		p = memchr(start_at, first,
   2754       1.1  christos 		    chain->off - pos.internal_.pos_in_chain);
   2755       1.1  christos 		if (p) {
   2756       1.1  christos 			pos.pos += p - start_at;
   2757       1.1  christos 			pos.internal_.pos_in_chain += p - start_at;
   2758       1.1  christos 			if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
   2759       1.1  christos 				if (end && pos.pos + (ev_ssize_t)len > end->pos)
   2760       1.1  christos 					goto not_found;
   2761       1.1  christos 				else
   2762       1.1  christos 					goto done;
   2763       1.1  christos 			}
   2764       1.1  christos 			++pos.pos;
   2765       1.1  christos 			++pos.internal_.pos_in_chain;
   2766       1.1  christos 			if (pos.internal_.pos_in_chain == chain->off) {
   2767       1.1  christos 				chain = pos.internal_.chain = chain->next;
   2768       1.1  christos 				pos.internal_.pos_in_chain = 0;
   2769       1.1  christos 			}
   2770       1.1  christos 		} else {
   2771       1.1  christos 			if (chain == last_chain)
   2772       1.1  christos 				goto not_found;
   2773       1.1  christos 			pos.pos += chain->off - pos.internal_.pos_in_chain;
   2774       1.1  christos 			chain = pos.internal_.chain = chain->next;
   2775       1.1  christos 			pos.internal_.pos_in_chain = 0;
   2776       1.1  christos 		}
   2777       1.1  christos 	}
   2778       1.1  christos 
   2779       1.1  christos not_found:
   2780       1.1  christos 	PTR_NOT_FOUND(&pos);
   2781       1.1  christos done:
   2782       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   2783       1.1  christos 	return pos;
   2784       1.1  christos }
   2785       1.1  christos 
   2786       1.1  christos int
   2787       1.1  christos evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
   2788       1.1  christos     struct evbuffer_ptr *start_at,
   2789       1.1  christos     struct evbuffer_iovec *vec, int n_vec)
   2790       1.1  christos {
   2791       1.1  christos 	struct evbuffer_chain *chain;
   2792       1.1  christos 	int idx = 0;
   2793       1.1  christos 	ev_ssize_t len_so_far = 0;
   2794       1.1  christos 
   2795       1.1  christos 	/* Avoid locking in trivial edge cases */
   2796       1.1  christos 	if (start_at && start_at->internal_.chain == NULL)
   2797       1.1  christos 		return 0;
   2798       1.1  christos 
   2799       1.1  christos 	EVBUFFER_LOCK(buffer);
   2800       1.1  christos 
   2801       1.1  christos 	if (start_at) {
   2802       1.1  christos 		chain = start_at->internal_.chain;
   2803       1.1  christos 		len_so_far = chain->off
   2804       1.1  christos 		    - start_at->internal_.pos_in_chain;
   2805       1.1  christos 		idx = 1;
   2806       1.1  christos 		if (n_vec > 0) {
   2807  1.1.1.10  christos 			vec[0].iov_base = (void *)(chain->buffer + chain->misalign
   2808  1.1.1.10  christos 			    + start_at->internal_.pos_in_chain);
   2809       1.1  christos 			vec[0].iov_len = len_so_far;
   2810       1.1  christos 		}
   2811       1.1  christos 		chain = chain->next;
   2812       1.1  christos 	} else {
   2813       1.1  christos 		chain = buffer->first;
   2814       1.1  christos 	}
   2815       1.1  christos 
   2816       1.1  christos 	if (n_vec == 0 && len < 0) {
   2817       1.1  christos 		/* If no vectors are provided and they asked for "everything",
   2818       1.1  christos 		 * pretend they asked for the actual available amount. */
   2819   1.1.1.3  christos 		len = buffer->total_len;
   2820   1.1.1.3  christos 		if (start_at) {
   2821   1.1.1.3  christos 			len -= start_at->pos;
   2822   1.1.1.3  christos 		}
   2823       1.1  christos 	}
   2824       1.1  christos 
   2825       1.1  christos 	while (chain) {
   2826       1.1  christos 		if (len >= 0 && len_so_far >= len)
   2827       1.1  christos 			break;
   2828       1.1  christos 		if (idx<n_vec) {
   2829  1.1.1.10  christos 			vec[idx].iov_base = (void *)(chain->buffer + chain->misalign);
   2830       1.1  christos 			vec[idx].iov_len = chain->off;
   2831       1.1  christos 		} else if (len<0) {
   2832       1.1  christos 			break;
   2833       1.1  christos 		}
   2834       1.1  christos 		++idx;
   2835       1.1  christos 		len_so_far += chain->off;
   2836       1.1  christos 		chain = chain->next;
   2837       1.1  christos 	}
   2838       1.1  christos 
   2839       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   2840       1.1  christos 
   2841       1.1  christos 	return idx;
   2842       1.1  christos }
   2843       1.1  christos 
   2844       1.1  christos 
   2845       1.1  christos int
   2846       1.1  christos evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
   2847       1.1  christos {
   2848       1.1  christos 	char *buffer;
   2849       1.1  christos 	size_t space;
   2850       1.1  christos 	int sz, result = -1;
   2851       1.1  christos 	va_list aq;
   2852       1.1  christos 	struct evbuffer_chain *chain;
   2853       1.1  christos 
   2854       1.1  christos 
   2855       1.1  christos 	EVBUFFER_LOCK(buf);
   2856       1.1  christos 
   2857       1.1  christos 	if (buf->freeze_end) {
   2858       1.1  christos 		goto done;
   2859       1.1  christos 	}
   2860       1.1  christos 
   2861       1.1  christos 	/* make sure that at least some space is available */
   2862       1.1  christos 	if ((chain = evbuffer_expand_singlechain(buf, 64)) == NULL)
   2863       1.1  christos 		goto done;
   2864       1.1  christos 
   2865       1.1  christos 	for (;;) {
   2866       1.1  christos #if 0
   2867       1.1  christos 		size_t used = chain->misalign + chain->off;
   2868       1.1  christos 		buffer = (char *)chain->buffer + chain->misalign + chain->off;
   2869       1.1  christos 		EVUTIL_ASSERT(chain->buffer_len >= used);
   2870       1.1  christos 		space = chain->buffer_len - used;
   2871       1.1  christos #endif
   2872       1.1  christos 		buffer = (char*) CHAIN_SPACE_PTR(chain);
   2873       1.1  christos 		space = (size_t) CHAIN_SPACE_LEN(chain);
   2874       1.1  christos 
   2875       1.1  christos #ifndef va_copy
   2876       1.1  christos #define	va_copy(dst, src)	memcpy(&(dst), &(src), sizeof(va_list))
   2877       1.1  christos #endif
   2878       1.1  christos 		va_copy(aq, ap);
   2879       1.1  christos 
   2880       1.1  christos 		sz = evutil_vsnprintf(buffer, space, fmt, aq);
   2881       1.1  christos 
   2882       1.1  christos 		va_end(aq);
   2883       1.1  christos 
   2884       1.1  christos 		if (sz < 0)
   2885       1.1  christos 			goto done;
   2886   1.1.1.3  christos 		if (INT_MAX >= EVBUFFER_CHAIN_MAX &&
   2887   1.1.1.3  christos 		    (size_t)sz >= EVBUFFER_CHAIN_MAX)
   2888   1.1.1.3  christos 			goto done;
   2889       1.1  christos 		if ((size_t)sz < space) {
   2890       1.1  christos 			chain->off += sz;
   2891       1.1  christos 			buf->total_len += sz;
   2892       1.1  christos 			buf->n_add_for_cb += sz;
   2893       1.1  christos 
   2894       1.1  christos 			advance_last_with_data(buf);
   2895       1.1  christos 			evbuffer_invoke_callbacks_(buf);
   2896       1.1  christos 			result = sz;
   2897       1.1  christos 			goto done;
   2898       1.1  christos 		}
   2899       1.1  christos 		if ((chain = evbuffer_expand_singlechain(buf, sz + 1)) == NULL)
   2900       1.1  christos 			goto done;
   2901       1.1  christos 	}
   2902       1.1  christos 	/* NOTREACHED */
   2903       1.1  christos 
   2904       1.1  christos done:
   2905       1.1  christos 	EVBUFFER_UNLOCK(buf);
   2906       1.1  christos 	return result;
   2907       1.1  christos }
   2908       1.1  christos 
   2909       1.1  christos int
   2910       1.1  christos evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
   2911       1.1  christos {
   2912       1.1  christos 	int res = -1;
   2913       1.1  christos 	va_list ap;
   2914       1.1  christos 
   2915       1.1  christos 	va_start(ap, fmt);
   2916       1.1  christos 	res = evbuffer_add_vprintf(buf, fmt, ap);
   2917       1.1  christos 	va_end(ap);
   2918       1.1  christos 
   2919       1.1  christos 	return (res);
   2920       1.1  christos }
   2921       1.1  christos 
   2922       1.1  christos int
   2923       1.1  christos evbuffer_add_reference(struct evbuffer *outbuf,
   2924       1.1  christos     const void *data, size_t datlen,
   2925       1.1  christos     evbuffer_ref_cleanup_cb cleanupfn, void *extra)
   2926       1.1  christos {
   2927       1.1  christos 	struct evbuffer_chain *chain;
   2928       1.1  christos 	struct evbuffer_chain_reference *info;
   2929       1.1  christos 	int result = -1;
   2930       1.1  christos 
   2931       1.1  christos 	chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_reference));
   2932       1.1  christos 	if (!chain)
   2933       1.1  christos 		return (-1);
   2934       1.1  christos 	chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
   2935  1.1.1.10  christos 	chain->buffer = (unsigned char *)data;
   2936       1.1  christos 	chain->buffer_len = datlen;
   2937       1.1  christos 	chain->off = datlen;
   2938       1.1  christos 
   2939       1.1  christos 	info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_reference, chain);
   2940       1.1  christos 	info->cleanupfn = cleanupfn;
   2941       1.1  christos 	info->extra = extra;
   2942       1.1  christos 
   2943       1.1  christos 	EVBUFFER_LOCK(outbuf);
   2944       1.1  christos 	if (outbuf->freeze_end) {
   2945       1.1  christos 		/* don't call chain_free; we do not want to actually invoke
   2946       1.1  christos 		 * the cleanup function */
   2947       1.1  christos 		mm_free(chain);
   2948       1.1  christos 		goto done;
   2949       1.1  christos 	}
   2950       1.1  christos 	evbuffer_chain_insert(outbuf, chain);
   2951       1.1  christos 	outbuf->n_add_for_cb += datlen;
   2952       1.1  christos 
   2953       1.1  christos 	evbuffer_invoke_callbacks_(outbuf);
   2954       1.1  christos 
   2955       1.1  christos 	result = 0;
   2956       1.1  christos done:
   2957       1.1  christos 	EVBUFFER_UNLOCK(outbuf);
   2958       1.1  christos 
   2959       1.1  christos 	return result;
   2960       1.1  christos }
   2961       1.1  christos 
   2962       1.1  christos /* TODO(niels): we may want to add to automagically convert to mmap, in
   2963       1.1  christos  * case evbuffer_remove() or evbuffer_pullup() are being used.
   2964       1.1  christos  */
   2965       1.1  christos struct evbuffer_file_segment *
   2966       1.1  christos evbuffer_file_segment_new(
   2967       1.1  christos 	int fd, ev_off_t offset, ev_off_t length, unsigned flags)
   2968       1.1  christos {
   2969       1.1  christos 	struct evbuffer_file_segment *seg =
   2970       1.1  christos 	    mm_calloc(sizeof(struct evbuffer_file_segment), 1);
   2971       1.1  christos 	if (!seg)
   2972       1.1  christos 		return NULL;
   2973       1.1  christos 	seg->refcnt = 1;
   2974       1.1  christos 	seg->fd = fd;
   2975       1.1  christos 	seg->flags = flags;
   2976       1.1  christos 	seg->file_offset = offset;
   2977       1.1  christos 	seg->cleanup_cb = NULL;
   2978       1.1  christos 	seg->cleanup_cb_arg = NULL;
   2979       1.1  christos #ifdef _WIN32
   2980       1.1  christos #ifndef lseek
   2981       1.1  christos #define lseek _lseeki64
   2982       1.1  christos #endif
   2983       1.1  christos #ifndef fstat
   2984       1.1  christos #define fstat _fstat
   2985       1.1  christos #endif
   2986       1.1  christos #ifndef stat
   2987       1.1  christos #define stat _stat
   2988       1.1  christos #endif
   2989       1.1  christos #endif
   2990       1.1  christos 	if (length == -1) {
   2991       1.1  christos 		struct stat st;
   2992       1.1  christos 		if (fstat(fd, &st) < 0)
   2993       1.1  christos 			goto err;
   2994       1.1  christos 		length = st.st_size;
   2995       1.1  christos 	}
   2996       1.1  christos 	seg->length = length;
   2997       1.1  christos 
   2998   1.1.1.3  christos 	if (offset < 0 || length < 0 ||
   2999   1.1.1.3  christos 	    ((ev_uint64_t)length > EVBUFFER_CHAIN_MAX) ||
   3000   1.1.1.3  christos 	    (ev_uint64_t)offset > (ev_uint64_t)(EVBUFFER_CHAIN_MAX - length))
   3001   1.1.1.3  christos 		goto err;
   3002   1.1.1.3  christos 
   3003       1.1  christos #if defined(USE_SENDFILE)
   3004       1.1  christos 	if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
   3005       1.1  christos 		seg->can_sendfile = 1;
   3006       1.1  christos 		goto done;
   3007       1.1  christos 	}
   3008       1.1  christos #endif
   3009       1.1  christos 
   3010       1.1  christos 	if (evbuffer_file_segment_materialize(seg)<0)
   3011       1.1  christos 		goto err;
   3012       1.1  christos 
   3013       1.1  christos #if defined(USE_SENDFILE)
   3014       1.1  christos done:
   3015       1.1  christos #endif
   3016       1.1  christos 	if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
   3017       1.1  christos 		EVTHREAD_ALLOC_LOCK(seg->lock, 0);
   3018       1.1  christos 	}
   3019       1.1  christos 	return seg;
   3020       1.1  christos err:
   3021       1.1  christos 	mm_free(seg);
   3022       1.1  christos 	return NULL;
   3023       1.1  christos }
   3024       1.1  christos 
   3025   1.1.1.2  christos #ifdef EVENT__HAVE_MMAP
   3026   1.1.1.2  christos static long
   3027   1.1.1.2  christos get_page_size(void)
   3028   1.1.1.2  christos {
   3029   1.1.1.2  christos #ifdef SC_PAGE_SIZE
   3030   1.1.1.2  christos 	return sysconf(SC_PAGE_SIZE);
   3031   1.1.1.2  christos #elif defined(_SC_PAGE_SIZE)
   3032   1.1.1.2  christos 	return sysconf(_SC_PAGE_SIZE);
   3033   1.1.1.2  christos #else
   3034   1.1.1.2  christos 	return 1;
   3035   1.1.1.2  christos #endif
   3036   1.1.1.2  christos }
   3037   1.1.1.2  christos #endif
   3038   1.1.1.2  christos 
   3039       1.1  christos /* DOCDOC */
   3040       1.1  christos /* Requires lock */
   3041       1.1  christos static int
   3042       1.1  christos evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
   3043       1.1  christos {
   3044       1.1  christos 	const unsigned flags = seg->flags;
   3045       1.1  christos 	const int fd = seg->fd;
   3046       1.1  christos 	const ev_off_t length = seg->length;
   3047       1.1  christos 	const ev_off_t offset = seg->file_offset;
   3048       1.1  christos 
   3049       1.1  christos 	if (seg->contents)
   3050       1.1  christos 		return 0; /* already materialized */
   3051       1.1  christos 
   3052       1.1  christos #if defined(EVENT__HAVE_MMAP)
   3053       1.1  christos 	if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
   3054       1.1  christos 		off_t offset_rounded = 0, offset_leftover = 0;
   3055       1.1  christos 		void *mapped;
   3056       1.1  christos 		if (offset) {
   3057       1.1  christos 			/* mmap implementations don't generally like us
   3058       1.1  christos 			 * to have an offset that isn't a round  */
   3059   1.1.1.2  christos 			long page_size = get_page_size();
   3060       1.1  christos 			if (page_size == -1)
   3061       1.1  christos 				goto err;
   3062       1.1  christos 			offset_leftover = offset % page_size;
   3063       1.1  christos 			offset_rounded = offset - offset_leftover;
   3064       1.1  christos 		}
   3065       1.1  christos 		mapped = mmap(NULL, length + offset_leftover,
   3066       1.1  christos 		    PROT_READ,
   3067       1.1  christos #ifdef MAP_NOCACHE
   3068       1.1  christos 		    MAP_NOCACHE | /* ??? */
   3069       1.1  christos #endif
   3070       1.1  christos #ifdef MAP_FILE
   3071       1.1  christos 		    MAP_FILE |
   3072       1.1  christos #endif
   3073       1.1  christos 		    MAP_PRIVATE,
   3074       1.1  christos 		    fd, offset_rounded);
   3075       1.1  christos 		if (mapped == MAP_FAILED) {
   3076       1.1  christos 			event_warn("%s: mmap(%d, %d, %zu) failed",
   3077       1.1  christos 			    __func__, fd, 0, (size_t)(offset + length));
   3078       1.1  christos 		} else {
   3079       1.1  christos 			seg->mapping = mapped;
   3080       1.1  christos 			seg->contents = (char*)mapped+offset_leftover;
   3081       1.1  christos 			seg->mmap_offset = 0;
   3082       1.1  christos 			seg->is_mapping = 1;
   3083       1.1  christos 			goto done;
   3084       1.1  christos 		}
   3085       1.1  christos 	}
   3086       1.1  christos #endif
   3087       1.1  christos #ifdef _WIN32
   3088       1.1  christos 	if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
   3089       1.1  christos 		intptr_t h = _get_osfhandle(fd);
   3090       1.1  christos 		HANDLE m;
   3091       1.1  christos 		ev_uint64_t total_size = length+offset;
   3092       1.1  christos 		if ((HANDLE)h == INVALID_HANDLE_VALUE)
   3093       1.1  christos 			goto err;
   3094       1.1  christos 		m = CreateFileMapping((HANDLE)h, NULL, PAGE_READONLY,
   3095       1.1  christos 		    (total_size >> 32), total_size & 0xfffffffful,
   3096       1.1  christos 		    NULL);
   3097       1.1  christos 		if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
   3098       1.1  christos 			seg->mapping_handle = m;
   3099       1.1  christos 			seg->mmap_offset = offset;
   3100       1.1  christos 			seg->is_mapping = 1;
   3101       1.1  christos 			goto done;
   3102       1.1  christos 		}
   3103       1.1  christos 	}
   3104       1.1  christos #endif
   3105       1.1  christos 	{
   3106       1.1  christos 		ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos;
   3107       1.1  christos 		ev_off_t read_so_far = 0;
   3108       1.1  christos 		char *mem;
   3109       1.1  christos 		int e;
   3110       1.1  christos 		ev_ssize_t n = 0;
   3111       1.1  christos 		if (!(mem = mm_malloc(length)))
   3112       1.1  christos 			goto err;
   3113       1.1  christos 		if (start_pos < 0) {
   3114       1.1  christos 			mm_free(mem);
   3115       1.1  christos 			goto err;
   3116       1.1  christos 		}
   3117       1.1  christos 		if (lseek(fd, offset, SEEK_SET) < 0) {
   3118       1.1  christos 			mm_free(mem);
   3119       1.1  christos 			goto err;
   3120       1.1  christos 		}
   3121       1.1  christos 		while (read_so_far < length) {
   3122       1.1  christos 			n = read(fd, mem+read_so_far, length-read_so_far);
   3123       1.1  christos 			if (n <= 0)
   3124       1.1  christos 				break;
   3125       1.1  christos 			read_so_far += n;
   3126       1.1  christos 		}
   3127       1.1  christos 
   3128       1.1  christos 		e = errno;
   3129       1.1  christos 		pos = lseek(fd, start_pos, SEEK_SET);
   3130       1.1  christos 		if (n < 0 || (n == 0 && length > read_so_far)) {
   3131       1.1  christos 			mm_free(mem);
   3132       1.1  christos 			errno = e;
   3133       1.1  christos 			goto err;
   3134       1.1  christos 		} else if (pos < 0) {
   3135       1.1  christos 			mm_free(mem);
   3136       1.1  christos 			goto err;
   3137       1.1  christos 		}
   3138       1.1  christos 
   3139       1.1  christos 		seg->contents = mem;
   3140       1.1  christos 	}
   3141       1.1  christos 
   3142       1.1  christos done:
   3143       1.1  christos 	return 0;
   3144       1.1  christos err:
   3145       1.1  christos 	return -1;
   3146       1.1  christos }
   3147       1.1  christos 
   3148       1.1  christos void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
   3149       1.1  christos 	evbuffer_file_segment_cleanup_cb cb, void* arg)
   3150       1.1  christos {
   3151       1.1  christos 	EVUTIL_ASSERT(seg->refcnt > 0);
   3152       1.1  christos 	seg->cleanup_cb = cb;
   3153       1.1  christos 	seg->cleanup_cb_arg = arg;
   3154       1.1  christos }
   3155       1.1  christos 
   3156       1.1  christos void
   3157       1.1  christos evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
   3158       1.1  christos {
   3159       1.1  christos 	int refcnt;
   3160       1.1  christos 	EVLOCK_LOCK(seg->lock, 0);
   3161       1.1  christos 	refcnt = --seg->refcnt;
   3162       1.1  christos 	EVLOCK_UNLOCK(seg->lock, 0);
   3163       1.1  christos 	if (refcnt > 0)
   3164       1.1  christos 		return;
   3165       1.1  christos 	EVUTIL_ASSERT(refcnt == 0);
   3166       1.1  christos 
   3167       1.1  christos 	if (seg->is_mapping) {
   3168       1.1  christos #ifdef _WIN32
   3169       1.1  christos 		CloseHandle(seg->mapping_handle);
   3170       1.1  christos #elif defined (EVENT__HAVE_MMAP)
   3171   1.1.1.2  christos 		off_t offset_leftover;
   3172   1.1.1.2  christos 		offset_leftover = seg->file_offset % get_page_size();
   3173   1.1.1.2  christos 		if (munmap(seg->mapping, seg->length + offset_leftover) == -1)
   3174       1.1  christos 			event_warn("%s: munmap failed", __func__);
   3175       1.1  christos #endif
   3176       1.1  christos 	} else if (seg->contents) {
   3177       1.1  christos 		mm_free(seg->contents);
   3178       1.1  christos 	}
   3179       1.1  christos 
   3180       1.1  christos 	if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
   3181       1.1  christos 		close(seg->fd);
   3182       1.1  christos 	}
   3183       1.1  christos 
   3184       1.1  christos 	if (seg->cleanup_cb) {
   3185       1.1  christos 		(*seg->cleanup_cb)((struct evbuffer_file_segment const*)seg,
   3186       1.1  christos 		    seg->flags, seg->cleanup_cb_arg);
   3187       1.1  christos 		seg->cleanup_cb = NULL;
   3188       1.1  christos 		seg->cleanup_cb_arg = NULL;
   3189       1.1  christos 	}
   3190       1.1  christos 
   3191       1.1  christos 	EVTHREAD_FREE_LOCK(seg->lock, 0);
   3192       1.1  christos 	mm_free(seg);
   3193       1.1  christos }
   3194       1.1  christos 
   3195       1.1  christos int
   3196       1.1  christos evbuffer_add_file_segment(struct evbuffer *buf,
   3197       1.1  christos     struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length)
   3198       1.1  christos {
   3199       1.1  christos 	struct evbuffer_chain *chain;
   3200       1.1  christos 	struct evbuffer_chain_file_segment *extra;
   3201       1.1  christos 	int can_use_sendfile = 0;
   3202       1.1  christos 
   3203       1.1  christos 	EVBUFFER_LOCK(buf);
   3204       1.1  christos 	EVLOCK_LOCK(seg->lock, 0);
   3205       1.1  christos 	if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
   3206       1.1  christos 		can_use_sendfile = 1;
   3207       1.1  christos 	} else {
   3208       1.1  christos 		if (!seg->contents) {
   3209       1.1  christos 			if (evbuffer_file_segment_materialize(seg)<0) {
   3210       1.1  christos 				EVLOCK_UNLOCK(seg->lock, 0);
   3211       1.1  christos 				EVBUFFER_UNLOCK(buf);
   3212       1.1  christos 				return -1;
   3213       1.1  christos 			}
   3214       1.1  christos 		}
   3215       1.1  christos 	}
   3216       1.1  christos 	EVLOCK_UNLOCK(seg->lock, 0);
   3217       1.1  christos 
   3218       1.1  christos 	if (buf->freeze_end)
   3219       1.1  christos 		goto err;
   3220       1.1  christos 
   3221       1.1  christos 	if (length < 0) {
   3222       1.1  christos 		if (offset > seg->length)
   3223       1.1  christos 			goto err;
   3224       1.1  christos 		length = seg->length - offset;
   3225       1.1  christos 	}
   3226       1.1  christos 
   3227       1.1  christos 	/* Can we actually add this? */
   3228       1.1  christos 	if (offset+length > seg->length)
   3229       1.1  christos 		goto err;
   3230       1.1  christos 
   3231       1.1  christos 	chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment));
   3232       1.1  christos 	if (!chain)
   3233       1.1  christos 		goto err;
   3234       1.1  christos 	extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
   3235       1.1  christos 
   3236       1.1  christos 	chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
   3237       1.1  christos 	if (can_use_sendfile && seg->can_sendfile) {
   3238       1.1  christos 		chain->flags |= EVBUFFER_SENDFILE;
   3239       1.1  christos 		chain->misalign = seg->file_offset + offset;
   3240       1.1  christos 		chain->off = length;
   3241       1.1  christos 		chain->buffer_len = chain->misalign + length;
   3242       1.1  christos 	} else if (seg->is_mapping) {
   3243       1.1  christos #ifdef _WIN32
   3244       1.1  christos 		ev_uint64_t total_offset = seg->mmap_offset+offset;
   3245       1.1  christos 		ev_uint64_t offset_rounded=0, offset_remaining=0;
   3246       1.1  christos 		LPVOID data;
   3247       1.1  christos 		if (total_offset) {
   3248       1.1  christos 			SYSTEM_INFO si;
   3249       1.1  christos 			memset(&si, 0, sizeof(si)); /* cargo cult */
   3250       1.1  christos 			GetSystemInfo(&si);
   3251       1.1  christos 			offset_remaining = total_offset % si.dwAllocationGranularity;
   3252       1.1  christos 			offset_rounded = total_offset - offset_remaining;
   3253       1.1  christos 		}
   3254       1.1  christos 		data = MapViewOfFile(
   3255       1.1  christos 			seg->mapping_handle,
   3256       1.1  christos 			FILE_MAP_READ,
   3257       1.1  christos 			offset_rounded >> 32,
   3258       1.1  christos 			offset_rounded & 0xfffffffful,
   3259       1.1  christos 			length + offset_remaining);
   3260       1.1  christos 		if (data == NULL) {
   3261       1.1  christos 			mm_free(chain);
   3262       1.1  christos 			goto err;
   3263       1.1  christos 		}
   3264       1.1  christos 		chain->buffer = (unsigned char*) data;
   3265       1.1  christos 		chain->buffer_len = length+offset_remaining;
   3266       1.1  christos 		chain->misalign = offset_remaining;
   3267       1.1  christos 		chain->off = length;
   3268       1.1  christos #else
   3269       1.1  christos 		chain->buffer = (unsigned char*)(seg->contents + offset);
   3270       1.1  christos 		chain->buffer_len = length;
   3271       1.1  christos 		chain->off = length;
   3272       1.1  christos #endif
   3273       1.1  christos 	} else {
   3274       1.1  christos 		chain->buffer = (unsigned char*)(seg->contents + offset);
   3275       1.1  christos 		chain->buffer_len = length;
   3276       1.1  christos 		chain->off = length;
   3277       1.1  christos 	}
   3278       1.1  christos 
   3279  1.1.1.10  christos 	EVLOCK_LOCK(seg->lock, 0);
   3280  1.1.1.10  christos 	++seg->refcnt;
   3281  1.1.1.10  christos 	EVLOCK_UNLOCK(seg->lock, 0);
   3282       1.1  christos 	extra->segment = seg;
   3283       1.1  christos 	buf->n_add_for_cb += length;
   3284       1.1  christos 	evbuffer_chain_insert(buf, chain);
   3285       1.1  christos 
   3286       1.1  christos 	evbuffer_invoke_callbacks_(buf);
   3287       1.1  christos 
   3288       1.1  christos 	EVBUFFER_UNLOCK(buf);
   3289       1.1  christos 
   3290       1.1  christos 	return 0;
   3291       1.1  christos err:
   3292       1.1  christos 	EVBUFFER_UNLOCK(buf);
   3293   1.1.1.3  christos 	evbuffer_file_segment_free(seg); /* Lowers the refcount */
   3294       1.1  christos 	return -1;
   3295       1.1  christos }
   3296       1.1  christos 
   3297       1.1  christos int
   3298       1.1  christos evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length)
   3299       1.1  christos {
   3300       1.1  christos 	struct evbuffer_file_segment *seg;
   3301       1.1  christos 	unsigned flags = EVBUF_FS_CLOSE_ON_FREE;
   3302       1.1  christos 	int r;
   3303       1.1  christos 
   3304       1.1  christos 	seg = evbuffer_file_segment_new(fd, offset, length, flags);
   3305       1.1  christos 	if (!seg)
   3306       1.1  christos 		return -1;
   3307       1.1  christos 	r = evbuffer_add_file_segment(buf, seg, 0, length);
   3308       1.1  christos 	if (r == 0)
   3309       1.1  christos 		evbuffer_file_segment_free(seg);
   3310       1.1  christos 	return r;
   3311       1.1  christos }
   3312       1.1  christos 
   3313  1.1.1.10  christos int
   3314       1.1  christos evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
   3315       1.1  christos {
   3316       1.1  christos 	EVBUFFER_LOCK(buffer);
   3317       1.1  christos 
   3318       1.1  christos 	if (!LIST_EMPTY(&buffer->callbacks))
   3319       1.1  christos 		evbuffer_remove_all_callbacks(buffer);
   3320       1.1  christos 
   3321       1.1  christos 	if (cb) {
   3322       1.1  christos 		struct evbuffer_cb_entry *ent =
   3323       1.1  christos 		    evbuffer_add_cb(buffer, NULL, cbarg);
   3324  1.1.1.10  christos 		if (!ent) {
   3325  1.1.1.10  christos 			EVBUFFER_UNLOCK(buffer);
   3326  1.1.1.10  christos 			return -1;
   3327  1.1.1.10  christos 		}
   3328       1.1  christos 		ent->cb.cb_obsolete = cb;
   3329       1.1  christos 		ent->flags |= EVBUFFER_CB_OBSOLETE;
   3330       1.1  christos 	}
   3331       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3332  1.1.1.10  christos 	return 0;
   3333       1.1  christos }
   3334       1.1  christos 
   3335       1.1  christos struct evbuffer_cb_entry *
   3336       1.1  christos evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
   3337       1.1  christos {
   3338       1.1  christos 	struct evbuffer_cb_entry *e;
   3339       1.1  christos 	if (! (e = mm_calloc(1, sizeof(struct evbuffer_cb_entry))))
   3340       1.1  christos 		return NULL;
   3341       1.1  christos 	EVBUFFER_LOCK(buffer);
   3342       1.1  christos 	e->cb.cb_func = cb;
   3343       1.1  christos 	e->cbarg = cbarg;
   3344       1.1  christos 	e->flags = EVBUFFER_CB_ENABLED;
   3345       1.1  christos 	LIST_INSERT_HEAD(&buffer->callbacks, e, next);
   3346       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3347       1.1  christos 	return e;
   3348       1.1  christos }
   3349       1.1  christos 
   3350       1.1  christos int
   3351       1.1  christos evbuffer_remove_cb_entry(struct evbuffer *buffer,
   3352       1.1  christos 			 struct evbuffer_cb_entry *ent)
   3353       1.1  christos {
   3354       1.1  christos 	EVBUFFER_LOCK(buffer);
   3355       1.1  christos 	LIST_REMOVE(ent, next);
   3356       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3357       1.1  christos 	mm_free(ent);
   3358       1.1  christos 	return 0;
   3359       1.1  christos }
   3360       1.1  christos 
   3361       1.1  christos int
   3362       1.1  christos evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
   3363       1.1  christos {
   3364       1.1  christos 	struct evbuffer_cb_entry *cbent;
   3365       1.1  christos 	int result = -1;
   3366       1.1  christos 	EVBUFFER_LOCK(buffer);
   3367       1.1  christos 	LIST_FOREACH(cbent, &buffer->callbacks, next) {
   3368       1.1  christos 		if (cb == cbent->cb.cb_func && cbarg == cbent->cbarg) {
   3369       1.1  christos 			result = evbuffer_remove_cb_entry(buffer, cbent);
   3370       1.1  christos 			goto done;
   3371       1.1  christos 		}
   3372       1.1  christos 	}
   3373       1.1  christos done:
   3374       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3375       1.1  christos 	return result;
   3376       1.1  christos }
   3377       1.1  christos 
   3378       1.1  christos int
   3379       1.1  christos evbuffer_cb_set_flags(struct evbuffer *buffer,
   3380       1.1  christos 		      struct evbuffer_cb_entry *cb, ev_uint32_t flags)
   3381       1.1  christos {
   3382       1.1  christos 	/* the user isn't allowed to mess with these. */
   3383       1.1  christos 	flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
   3384       1.1  christos 	EVBUFFER_LOCK(buffer);
   3385       1.1  christos 	cb->flags |= flags;
   3386       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3387       1.1  christos 	return 0;
   3388       1.1  christos }
   3389       1.1  christos 
   3390       1.1  christos int
   3391       1.1  christos evbuffer_cb_clear_flags(struct evbuffer *buffer,
   3392       1.1  christos 		      struct evbuffer_cb_entry *cb, ev_uint32_t flags)
   3393       1.1  christos {
   3394       1.1  christos 	/* the user isn't allowed to mess with these. */
   3395       1.1  christos 	flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
   3396       1.1  christos 	EVBUFFER_LOCK(buffer);
   3397       1.1  christos 	cb->flags &= ~flags;
   3398       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3399       1.1  christos 	return 0;
   3400       1.1  christos }
   3401       1.1  christos 
   3402       1.1  christos int
   3403       1.1  christos evbuffer_freeze(struct evbuffer *buffer, int start)
   3404       1.1  christos {
   3405       1.1  christos 	EVBUFFER_LOCK(buffer);
   3406       1.1  christos 	if (start)
   3407       1.1  christos 		buffer->freeze_start = 1;
   3408       1.1  christos 	else
   3409       1.1  christos 		buffer->freeze_end = 1;
   3410       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3411       1.1  christos 	return 0;
   3412       1.1  christos }
   3413       1.1  christos 
   3414       1.1  christos int
   3415       1.1  christos evbuffer_unfreeze(struct evbuffer *buffer, int start)
   3416       1.1  christos {
   3417       1.1  christos 	EVBUFFER_LOCK(buffer);
   3418       1.1  christos 	if (start)
   3419       1.1  christos 		buffer->freeze_start = 0;
   3420       1.1  christos 	else
   3421       1.1  christos 		buffer->freeze_end = 0;
   3422       1.1  christos 	EVBUFFER_UNLOCK(buffer);
   3423       1.1  christos 	return 0;
   3424       1.1  christos }
   3425       1.1  christos 
   3426       1.1  christos #if 0
   3427       1.1  christos void
   3428       1.1  christos evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
   3429       1.1  christos {
   3430       1.1  christos 	if (!(cb->flags & EVBUFFER_CB_SUSPENDED)) {
   3431       1.1  christos 		cb->size_before_suspend = evbuffer_get_length(buffer);
   3432       1.1  christos 		cb->flags |= EVBUFFER_CB_SUSPENDED;
   3433       1.1  christos 	}
   3434       1.1  christos }
   3435       1.1  christos 
   3436       1.1  christos void
   3437       1.1  christos evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
   3438       1.1  christos {
   3439       1.1  christos 	if ((cb->flags & EVBUFFER_CB_SUSPENDED)) {
   3440       1.1  christos 		unsigned call = (cb->flags & EVBUFFER_CB_CALL_ON_UNSUSPEND);
   3441       1.1  christos 		size_t sz = cb->size_before_suspend;
   3442       1.1  christos 		cb->flags &= ~(EVBUFFER_CB_SUSPENDED|
   3443       1.1  christos 			       EVBUFFER_CB_CALL_ON_UNSUSPEND);
   3444       1.1  christos 		cb->size_before_suspend = 0;
   3445       1.1  christos 		if (call && (cb->flags & EVBUFFER_CB_ENABLED)) {
   3446       1.1  christos 			cb->cb(buffer, sz, evbuffer_get_length(buffer), cb->cbarg);
   3447       1.1  christos 		}
   3448       1.1  christos 	}
   3449       1.1  christos }
   3450       1.1  christos #endif
   3451       1.1  christos 
   3452   1.1.1.2  christos int
   3453   1.1.1.2  christos evbuffer_get_callbacks_(struct evbuffer *buffer, struct event_callback **cbs,
   3454   1.1.1.2  christos     int max_cbs)
   3455   1.1.1.2  christos {
   3456   1.1.1.2  christos 	int r = 0;
   3457   1.1.1.2  christos 	EVBUFFER_LOCK(buffer);
   3458   1.1.1.2  christos 	if (buffer->deferred_cbs) {
   3459   1.1.1.2  christos 		if (max_cbs < 1) {
   3460   1.1.1.2  christos 			r = -1;
   3461   1.1.1.2  christos 			goto done;
   3462   1.1.1.2  christos 		}
   3463   1.1.1.2  christos 		cbs[0] = &buffer->deferred;
   3464   1.1.1.2  christos 		r = 1;
   3465   1.1.1.2  christos 	}
   3466   1.1.1.2  christos done:
   3467   1.1.1.2  christos 	EVBUFFER_UNLOCK(buffer);
   3468   1.1.1.2  christos 	return r;
   3469   1.1.1.2  christos }
   3470