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