nghttp2/src/libevent_util.cc

163 lines
4.0 KiB
C++

/*
* 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