| /* |
| * nghttp2 - HTTP/2 C Library |
| * |
| * Copyright (c) 2014 Tatsuhiro Tsujikawa |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| #include "libevent_util.h" |
| |
| #include <cstring> |
| #include <algorithm> |
| |
| namespace nghttp2 { |
| |
| namespace util { |
| |
| EvbufferBuffer::EvbufferBuffer() |
| : evbuffer_(nullptr), |
| bucket_(nullptr), |
| buf_(nullptr), |
| bufmax_(0), |
| buflen_(0), |
| limit_(0), |
| writelen_(0) {} |
| |
| EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, |
| ssize_t limit) |
| : evbuffer_(evbuffer), |
| bucket_(limit == -1 ? nullptr : evbuffer_new()), |
| buf_(buf), |
| bufmax_(bufmax), |
| buflen_(0), |
| limit_(limit), |
| writelen_(0) {} |
| |
| void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, |
| ssize_t limit) { |
| evbuffer_ = evbuffer; |
| buf_ = buf; |
| if (limit != -1 && !bucket_) { |
| bucket_ = evbuffer_new(); |
| } |
| bufmax_ = bufmax; |
| buflen_ = 0; |
| limit_ = limit; |
| writelen_ = 0; |
| } |
| |
| EvbufferBuffer::~EvbufferBuffer() { |
| if (bucket_) { |
| evbuffer_free(bucket_); |
| } |
| } |
| |
| int EvbufferBuffer::write_buffer() { |
| for (auto pos = buf_, end = buf_ + buflen_; pos < end;) { |
| // To avoid merging chunks in evbuffer, we first add to temporal |
| // buffer bucket_ and then move its chain to evbuffer_. |
| auto nwrite = std::min(end - pos, limit_); |
| auto rv = evbuffer_add(bucket_, pos, nwrite); |
| if (rv == -1) { |
| return -1; |
| } |
| rv = evbuffer_add_buffer(evbuffer_, bucket_); |
| if (rv == -1) { |
| return -1; |
| } |
| pos += nwrite; |
| } |
| return 0; |
| } |
| |
| int EvbufferBuffer::flush() { |
| int rv; |
| if (buflen_ > 0) { |
| if (limit_ == -1) { |
| rv = evbuffer_add(evbuffer_, buf_, buflen_); |
| } else { |
| rv = write_buffer(); |
| } |
| if (rv == -1) { |
| return -1; |
| } |
| writelen_ += buflen_; |
| buflen_ = 0; |
| } |
| return 0; |
| } |
| |
| int EvbufferBuffer::add(const uint8_t *data, size_t datalen) { |
| int rv; |
| if (buflen_ + datalen > bufmax_) { |
| if (buflen_ > 0) { |
| if (limit_ == -1) { |
| rv = evbuffer_add(evbuffer_, buf_, buflen_); |
| } else { |
| rv = write_buffer(); |
| } |
| if (rv == -1) { |
| return -1; |
| } |
| writelen_ += buflen_; |
| buflen_ = 0; |
| } |
| if (datalen > bufmax_) { |
| if (limit_ == -1) { |
| rv = evbuffer_add(evbuffer_, data, datalen); |
| } else { |
| rv = write_buffer(); |
| } |
| if (rv == -1) { |
| return -1; |
| } |
| writelen_ += buflen_; |
| return 0; |
| } |
| } |
| memcpy(buf_ + buflen_, data, datalen); |
| buflen_ += datalen; |
| return 0; |
| } |
| |
| size_t EvbufferBuffer::get_buflen() const { return buflen_; } |
| |
| size_t EvbufferBuffer::get_writelen() const { return writelen_; } |
| |
| void bev_enable_unless(bufferevent *bev, int events) { |
| if ((bufferevent_get_enabled(bev) & events) == events) { |
| return; |
| } |
| |
| bufferevent_enable(bev, events); |
| } |
| |
| void bev_disable_unless(bufferevent *bev, int events) { |
| if ((bufferevent_get_enabled(bev) & events) == 0) { |
| return; |
| } |
| |
| bufferevent_disable(bev, events); |
| } |
| |
| } // namespace util |
| |
| } // namespace nghttp2 |