xref: /third_party/nghttp2/src/libevent_util.cc (revision 2c593315)
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