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