• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 namespace nghttp2 {
31 
32 namespace util {
33 
EvbufferBuffer()34 EvbufferBuffer::EvbufferBuffer()
35     : evbuffer_(nullptr),
36       bucket_(nullptr),
37       buf_(nullptr),
38       bufmax_(0),
39       buflen_(0),
40       limit_(0),
41       writelen_(0) {}
42 
EvbufferBuffer(evbuffer * evbuffer,uint8_t * buf,size_t bufmax,ssize_t limit)43 EvbufferBuffer::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 
reset(evbuffer * evbuffer,uint8_t * buf,size_t bufmax,ssize_t limit)53 void 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 
~EvbufferBuffer()66 EvbufferBuffer::~EvbufferBuffer() {
67   if (bucket_) {
68     evbuffer_free(bucket_);
69   }
70 }
71 
write_buffer()72 int 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 
flush()90 int 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 
add(const uint8_t * data,size_t datalen)107 int 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 
get_buflen() const140 size_t EvbufferBuffer::get_buflen() const { return buflen_; }
141 
get_writelen() const142 size_t EvbufferBuffer::get_writelen() const { return writelen_; }
143 
bev_enable_unless(bufferevent * bev,int events)144 void 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 
bev_disable_unless(bufferevent * bev,int events)152 void 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