1/* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2014 Tatsuhiro Tsujikawa 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25#include "libevent_util.h" 26 27#include <cstring> 28#include <algorithm> 29 30namespace nghttp2 { 31 32namespace util { 33 34EvbufferBuffer::EvbufferBuffer() 35 : evbuffer_(nullptr), 36 bucket_(nullptr), 37 buf_(nullptr), 38 bufmax_(0), 39 buflen_(0), 40 limit_(0), 41 writelen_(0) {} 42 43EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, 44 ssize_t limit) 45 : evbuffer_(evbuffer), 46 bucket_(limit == -1 ? nullptr : evbuffer_new()), 47 buf_(buf), 48 bufmax_(bufmax), 49 buflen_(0), 50 limit_(limit), 51 writelen_(0) {} 52 53void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, 54 ssize_t limit) { 55 evbuffer_ = evbuffer; 56 buf_ = buf; 57 if (limit != -1 && !bucket_) { 58 bucket_ = evbuffer_new(); 59 } 60 bufmax_ = bufmax; 61 buflen_ = 0; 62 limit_ = limit; 63 writelen_ = 0; 64} 65 66EvbufferBuffer::~EvbufferBuffer() { 67 if (bucket_) { 68 evbuffer_free(bucket_); 69 } 70} 71 72int EvbufferBuffer::write_buffer() { 73 for (auto pos = buf_, end = buf_ + buflen_; pos < end;) { 74 // To avoid merging chunks in evbuffer, we first add to temporal 75 // buffer bucket_ and then move its chain to evbuffer_. 76 auto nwrite = std::min(end - pos, limit_); 77 auto rv = evbuffer_add(bucket_, pos, nwrite); 78 if (rv == -1) { 79 return -1; 80 } 81 rv = evbuffer_add_buffer(evbuffer_, bucket_); 82 if (rv == -1) { 83 return -1; 84 } 85 pos += nwrite; 86 } 87 return 0; 88} 89 90int EvbufferBuffer::flush() { 91 int rv; 92 if (buflen_ > 0) { 93 if (limit_ == -1) { 94 rv = evbuffer_add(evbuffer_, buf_, buflen_); 95 } else { 96 rv = write_buffer(); 97 } 98 if (rv == -1) { 99 return -1; 100 } 101 writelen_ += buflen_; 102 buflen_ = 0; 103 } 104 return 0; 105} 106 107int EvbufferBuffer::add(const uint8_t *data, size_t datalen) { 108 int rv; 109 if (buflen_ + datalen > bufmax_) { 110 if (buflen_ > 0) { 111 if (limit_ == -1) { 112 rv = evbuffer_add(evbuffer_, buf_, buflen_); 113 } else { 114 rv = write_buffer(); 115 } 116 if (rv == -1) { 117 return -1; 118 } 119 writelen_ += buflen_; 120 buflen_ = 0; 121 } 122 if (datalen > bufmax_) { 123 if (limit_ == -1) { 124 rv = evbuffer_add(evbuffer_, data, datalen); 125 } else { 126 rv = write_buffer(); 127 } 128 if (rv == -1) { 129 return -1; 130 } 131 writelen_ += buflen_; 132 return 0; 133 } 134 } 135 memcpy(buf_ + buflen_, data, datalen); 136 buflen_ += datalen; 137 return 0; 138} 139 140size_t EvbufferBuffer::get_buflen() const { return buflen_; } 141 142size_t EvbufferBuffer::get_writelen() const { return writelen_; } 143 144void bev_enable_unless(bufferevent *bev, int events) { 145 if ((bufferevent_get_enabled(bev) & events) == events) { 146 return; 147 } 148 149 bufferevent_enable(bev, events); 150} 151 152void bev_disable_unless(bufferevent *bev, int events) { 153 if ((bufferevent_get_enabled(bev) & events) == 0) { 154 return; 155 } 156 157 bufferevent_disable(bev, events); 158} 159 160} // namespace util 161 162} // namespace nghttp2 163