tizen 2.4 release
[external/nghttp2.git] / src / libevent_util.cc
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
34 EvbufferBuffer::EvbufferBuffer()
35     : evbuffer_(nullptr), bucket_(nullptr), buf_(nullptr), bufmax_(0),
36       buflen_(0), limit_(0), writelen_(0) {}
37
38 EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
39                                ssize_t limit)
40     : evbuffer_(evbuffer), bucket_(limit == -1 ? nullptr : evbuffer_new()),
41       buf_(buf), bufmax_(bufmax), buflen_(0), limit_(limit), writelen_(0) {}
42
43 void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
44                            ssize_t limit) {
45   evbuffer_ = evbuffer;
46   buf_ = buf;
47   if (limit != -1 && !bucket_) {
48     bucket_ = evbuffer_new();
49   }
50   bufmax_ = bufmax;
51   buflen_ = 0;
52   limit_ = limit;
53   writelen_ = 0;
54 }
55
56 EvbufferBuffer::~EvbufferBuffer() {
57   if (bucket_) {
58     evbuffer_free(bucket_);
59   }
60 }
61
62 int EvbufferBuffer::write_buffer() {
63   for (auto pos = buf_, end = buf_ + buflen_; pos < end;) {
64     // To avoid merging chunks in evbuffer, we first add to temporal
65     // buffer bucket_ and then move its chain to evbuffer_.
66     auto nwrite = std::min(end - pos, limit_);
67     auto rv = evbuffer_add(bucket_, pos, nwrite);
68     if (rv == -1) {
69       return -1;
70     }
71     rv = evbuffer_add_buffer(evbuffer_, bucket_);
72     if (rv == -1) {
73       return -1;
74     }
75     pos += nwrite;
76   }
77   return 0;
78 }
79
80 int EvbufferBuffer::flush() {
81   int rv;
82   if (buflen_ > 0) {
83     if (limit_ == -1) {
84       rv = evbuffer_add(evbuffer_, buf_, buflen_);
85     } else {
86       rv = write_buffer();
87     }
88     if (rv == -1) {
89       return -1;
90     }
91     writelen_ += buflen_;
92     buflen_ = 0;
93   }
94   return 0;
95 }
96
97 int EvbufferBuffer::add(const uint8_t *data, size_t datalen) {
98   int rv;
99   if (buflen_ + datalen > bufmax_) {
100     if (buflen_ > 0) {
101       if (limit_ == -1) {
102         rv = evbuffer_add(evbuffer_, buf_, buflen_);
103       } else {
104         rv = write_buffer();
105       }
106       if (rv == -1) {
107         return -1;
108       }
109       writelen_ += buflen_;
110       buflen_ = 0;
111     }
112     if (datalen > bufmax_) {
113       if (limit_ == -1) {
114         rv = evbuffer_add(evbuffer_, data, datalen);
115       } else {
116         rv = write_buffer();
117       }
118       if (rv == -1) {
119         return -1;
120       }
121       writelen_ += buflen_;
122       return 0;
123     }
124   }
125   memcpy(buf_ + buflen_, data, datalen);
126   buflen_ += datalen;
127   return 0;
128 }
129
130 size_t EvbufferBuffer::get_buflen() const { return buflen_; }
131
132 size_t EvbufferBuffer::get_writelen() const { return writelen_; }
133
134 void bev_enable_unless(bufferevent *bev, int events) {
135   if ((bufferevent_get_enabled(bev) & events) == events) {
136     return;
137   }
138
139   bufferevent_enable(bev, events);
140 }
141
142 void bev_disable_unless(bufferevent *bev, int events) {
143   if ((bufferevent_get_enabled(bev) & events) == 0) {
144     return;
145   }
146
147   bufferevent_disable(bev, events);
148 }
149
150 } // namespace util
151
152 } // namespace nghttp2