1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL. If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so. If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact: Jari Sundell <jaris@ifi.uio.no>
33 //
34 // Skomakerveien 33
35 // 3185 Skoppum, NORWAY
36
37 #ifndef LIBTORRENT_NET_PROTOCOL_BUFFER_H
38 #define LIBTORRENT_NET_PROTOCOL_BUFFER_H
39
40 #include <memory>
41 #include <inttypes.h>
42 #include <netinet/in.h>
43
44 #include "torrent/exceptions.h"
45
46 namespace torrent {
47
48 template <uint16_t tmpl_size>
49 class ProtocolBuffer {
50 public:
51 typedef uint8_t value_type;
52 typedef value_type* iterator;
53 typedef uint16_t size_type;
54 typedef int16_t difference_type;
55
reset()56 void reset() { m_position = m_end = begin(); }
reset_position()57 void reset_position() { m_position = m_buffer; }
58 bool consume(difference_type v);
59
set_position_itr(iterator itr)60 void set_position_itr(iterator itr) { m_position = itr; }
61
set_end(size_type v)62 void set_end(size_type v) { m_end = m_buffer + v; }
set_end_itr(iterator itr)63 void set_end_itr(iterator itr) { m_end = itr; }
move_end(difference_type v)64 difference_type move_end(difference_type v) { m_end += v; return v; }
65
read_8()66 uint8_t read_8() { return *m_position++; }
peek_8()67 uint8_t peek_8() { return *m_position; }
68 uint16_t read_16();
69 uint16_t peek_16();
70 uint32_t read_32();
71 uint32_t peek_32();
read_64()72 uint64_t read_64() { return read_int<uint64_t>(); }
peek_64()73 uint64_t peek_64() { return peek_int<uint64_t>(); }
74
peek_8_at(size_type pos)75 uint8_t peek_8_at(size_type pos) { return *(m_position + pos); }
76
77 template <typename Out>
78 void read_range(Out first, Out last);
79
80 template <typename Out>
81 void read_len(Out start, unsigned int len);
82
83 template <typename T>
84 inline T read_int();
85
86 template <typename T>
87 inline T peek_int();
88
write_8(uint8_t v)89 void write_8(uint8_t v) { *m_end++ = v; validate_end(); }
90 void write_16(uint16_t v);
91 void write_32(uint32_t v);
92 void write_32_n(uint32_t v);
write_64(uint64_t v)93 void write_64(uint64_t v) { write_int<uint64_t>(v); }
94
95 template <typename T>
96 inline void write_int(T t);
97
98 template <typename In>
99 void write_range(In first, In last);
100
101 template <typename In>
102 void write_len(In start, unsigned int len);
103
begin()104 iterator begin() { return m_buffer; }
position()105 iterator position() { return m_position; }
end()106 iterator end() { return m_end; }
107
size_position()108 size_type size_position() const { return m_position - m_buffer; }
size_end()109 size_type size_end() const { return m_end - m_buffer; }
remaining()110 size_type remaining() const { return m_end - m_position; }
reserved()111 size_type reserved() const { return tmpl_size; }
reserved_left()112 size_type reserved_left() const { return reserved() - size_end(); }
113
114 void move_unused();
115
validate_position()116 void validate_position() const {
117 #ifdef USE_EXTRA_DEBUG
118 if (m_position > m_buffer + tmpl_size)
119 throw internal_error("ProtocolBuffer tried to read beyond scope of the buffer.");
120 if (m_position > m_end)
121 throw internal_error("ProtocolBuffer tried to read beyond end of the buffer.");
122 #endif
123 }
124
validate_end()125 void validate_end() const {
126 #ifdef USE_EXTRA_DEBUG
127 if (m_end > m_buffer + tmpl_size)
128 throw internal_error("ProtocolBuffer tried to write beyond scope of the buffer.");
129 #endif
130 }
131
132 private:
133 iterator m_position;
134 iterator m_end;
135 value_type m_buffer[tmpl_size];
136 };
137
138 template <uint16_t tmpl_size>
139 inline bool
consume(difference_type v)140 ProtocolBuffer<tmpl_size>::consume(difference_type v) {
141 m_position += v;
142
143 if (remaining())
144 return false;
145
146 return true;
147 }
148
149 template <uint16_t tmpl_size>
150 inline uint16_t
read_16()151 ProtocolBuffer<tmpl_size>::read_16() {
152 #ifndef USE_ALIGNED
153 uint16_t t = ntohs(*reinterpret_cast<uint16_t*>(m_position));
154 m_position += sizeof(uint16_t);
155
156 return t;
157 #else
158 return read_int<uint16_t>();
159 #endif
160 }
161
162 template <uint16_t tmpl_size>
163 inline uint16_t
peek_16()164 ProtocolBuffer<tmpl_size>::peek_16() {
165 #ifndef USE_ALIGNED
166 return ntohs(*reinterpret_cast<uint16_t*>(m_position));
167 #else
168 return peek_int<uint16_t>();
169 #endif
170 }
171
172 template <uint16_t tmpl_size>
173 inline uint32_t
read_32()174 ProtocolBuffer<tmpl_size>::read_32() {
175 #ifndef USE_ALIGNED
176 uint32_t t = ntohl(*reinterpret_cast<uint32_t*>(m_position));
177 m_position += sizeof(uint32_t);
178
179 return t;
180 #else
181 return read_int<uint32_t>();
182 #endif
183 }
184
185 template <uint16_t tmpl_size>
186 inline uint32_t
peek_32()187 ProtocolBuffer<tmpl_size>::peek_32() {
188 #ifndef USE_ALIGNED
189 return ntohl(*reinterpret_cast<uint32_t*>(m_position));
190 #else
191 return peek_int<uint32_t>();
192 #endif
193 }
194
195 template <uint16_t tmpl_size>
196 template <typename T>
197 inline T
read_int()198 ProtocolBuffer<tmpl_size>::read_int() {
199 T t = T();
200
201 for (iterator last = m_position + sizeof(T); m_position != last; ++m_position)
202 t = (t << 8) + *m_position;
203
204 return t;
205 }
206
207 template <uint16_t tmpl_size>
208 template <typename T>
209 inline T
peek_int()210 ProtocolBuffer<tmpl_size>::peek_int() {
211 T t = T();
212
213 for (iterator itr = m_position, last = m_position + sizeof(T); itr != last; ++itr)
214 t = (t << 8) + *itr;
215
216 return t;
217 }
218
219 template <uint16_t tmpl_size>
220 inline void
write_16(uint16_t v)221 ProtocolBuffer<tmpl_size>::write_16(uint16_t v) {
222 #ifndef USE_ALIGNED
223 *reinterpret_cast<uint16_t*>(m_end) = htons(v);
224 m_end += sizeof(uint16_t);
225
226 validate_end();
227 #else
228 write_int<uint16_t>(v);
229 #endif
230 }
231
232 template <uint16_t tmpl_size>
233 inline void
write_32(uint32_t v)234 ProtocolBuffer<tmpl_size>::write_32(uint32_t v) {
235 #ifndef USE_ALIGNED
236 *reinterpret_cast<uint32_t*>(m_end) = htonl(v);
237 m_end += sizeof(uint32_t);
238
239 validate_end();
240 #else
241 write_int<uint32_t>(v);
242 #endif
243 }
244
245 template <uint16_t tmpl_size>
246 inline void
write_32_n(uint32_t v)247 ProtocolBuffer<tmpl_size>::write_32_n(uint32_t v) {
248 *reinterpret_cast<uint32_t*>(m_end) = v;
249 m_end += sizeof(uint32_t);
250
251 validate_end();
252 }
253
254 template <uint16_t tmpl_size>
255 template <typename Out>
256 void
read_range(Out first,Out last)257 ProtocolBuffer<tmpl_size>::read_range(Out first, Out last) {
258 for ( ; first != last; ++m_position, ++first)
259 *first = *m_position;
260
261 validate_position();
262 }
263
264 template <uint16_t tmpl_size>
265 template <typename Out>
266 void
read_len(Out start,unsigned int len)267 ProtocolBuffer<tmpl_size>::read_len(Out start, unsigned int len) {
268 for ( ; len > 0; ++m_position, ++start, --len)
269 *start = *m_position;
270
271 validate_position();
272 }
273
274 template <uint16_t tmpl_size>
275 template <typename T>
276 inline void
write_int(T v)277 ProtocolBuffer<tmpl_size>::write_int(T v) {
278 for (iterator itr = m_end + sizeof(T); itr != m_end; v >>= 8)
279 *(--itr) = v;
280
281 m_end += sizeof(T);
282 validate_end();
283 }
284
285 template <uint16_t tmpl_size>
286 template <typename In>
287 void
write_range(In first,In last)288 ProtocolBuffer<tmpl_size>::write_range(In first, In last) {
289 for ( ; first != last; ++m_end, ++first)
290 *m_end = *first;
291
292 validate_end();
293 }
294
295 template <uint16_t tmpl_size>
296 template <typename In>
297 void
write_len(In start,unsigned int len)298 ProtocolBuffer<tmpl_size>::write_len(In start, unsigned int len) {
299 for ( ; len > 0; ++m_end, ++start, --len)
300 *m_end = *start;
301
302 validate_end();
303 }
304
305 template <uint16_t tmpl_size>
306 void
move_unused()307 ProtocolBuffer<tmpl_size>::move_unused() {
308 std::memmove(begin(), position(), remaining());
309
310 set_end(remaining());
311 reset_position();
312 }
313
314 }
315
316 #endif
317