monotone

monotone Mtn Source Tree

Root/netio.hh

1#ifndef __NETIO_HH__
2#define __NETIO_HH__
3
4// Copyright (C) 2004 Graydon Hoare <graydon@pobox.com>
5//
6// This program is made available under the GNU GPL version 2.0 or
7// greater. See the accompanying file COPYING for details.
8//
9// This program is distributed WITHOUT ANY WARRANTY; without even the
10// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11// PURPOSE.
12
13// all network i/o decoding and encoding in netcmd and merkle is done using
14// the primitives in this header. it has to be very correct.
15
16#include <boost/static_assert.hpp>
17
18#include "numeric_vocab.hh"
19#include "sanity.hh"
20#include "string_queue.hh"
21
22struct bad_decode {
23 bad_decode(i18n_format const & fmt) : what(fmt.str()) {}
24 std::string what;
25};
26
27inline void
28require_bytes(std::string const & str,
29 size_t pos,
30 size_t len,
31 std::string const & name)
32{
33 // if you've gone past the end of the buffer, there's a logic error,
34 // and this program is not safe to keep running. shut down.
35 I(pos < str.size() || (pos == str.size() && len == 0));
36 // otherwise make sure there's room for this decode operation, but
37 // use a recoverable exception type.
38 if (len == 0)
39 return;
40 if (str.size() < pos + len)
41 throw bad_decode(F("need %d bytes to decode %s at %d, only have %d")
42 % len % name % pos % (str.size() - pos));
43}
44
45inline void
46require_bytes(string_queue const & str,
47 size_t pos,
48 size_t len,
49 std::string const & name)
50{
51 // if you've gone past the end of the buffer, there's a logic error,
52 // and this program is not safe to keep running. shut down.
53 I(pos < str.size() || (pos == str.size() && len == 0));
54 // otherwise make sure there's room for this decode operation, but
55 // use a recoverable exception type.
56 if (len == 0)
57 return;
58 if (str.size() < pos + len)
59 throw bad_decode(F("need %d bytes to decode %s at %d, only have %d")
60 % len % name % pos % (str.size() - pos));
61}
62
63template <typename T>
64inline bool
65try_extract_datum_uleb128(std::string const & in,
66 size_t & pos,
67 std::string const & name,
68 T & out)
69{
70 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
71 size_t shift = 0;
72 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
73 out = 0;
74 while (maxbytes > 0)
75 {
76 if (pos >= in.size())
77 return false;
78 T curr = widen<T,u8>(in[pos]);
79 ++pos;
80 out |= ((static_cast<u8>(curr)
81 & static_cast<u8>(0x7f)) << shift);
82 bool finished = ! static_cast<bool>(static_cast<u8>(curr)
83 & static_cast<u8>(0x80));
84 if (finished)
85 break;
86 else if (maxbytes == 1)
87 throw bad_decode(F("overflow while decoding variable length integer '%s' into a %d-byte field")
88 % name % maxbytes);
89 else
90 {
91 --maxbytes;
92 shift += 7;
93 }
94 }
95 return true;
96}
97
98template <typename T>
99inline bool
100try_extract_datum_uleb128(string_queue const & in,
101 size_t & pos,
102 std::string const & name,
103 T & out)
104{
105 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
106 size_t shift = 0;
107 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
108 out = 0;
109 while (maxbytes > 0)
110 {
111 if (pos >= in.size())
112 return false;
113 T curr = widen<T,u8>(in[pos]);
114 ++pos;
115 out |= ((static_cast<u8>(curr)
116 & static_cast<u8>(0x7f)) << shift);
117 bool finished = ! static_cast<bool>(static_cast<u8>(curr)
118 & static_cast<u8>(0x80));
119 if (finished)
120 break;
121 else if (maxbytes == 1)
122 throw bad_decode(F("overflow while decoding variable length integer '%s' into a %d-byte field")
123 % name % maxbytes);
124 else
125 {
126 --maxbytes;
127 shift += 7;
128 }
129 }
130 return true;
131}
132
133template <typename T>
134inline T
135extract_datum_uleb128(std::string const & in,
136 size_t & pos,
137 std::string const & name)
138{
139 T out;
140 size_t tpos = pos;
141 if (! try_extract_datum_uleb128(in, tpos, name, out))
142 throw bad_decode(F("ran out of bytes reading variable length integer '%s' at pos %d")
143 % name % pos);
144 pos = tpos;
145 return out;
146}
147
148template <typename T>
149inline void
150insert_datum_uleb128(T in, std::string & out)
151{
152 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
153 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
154 while (maxbytes > 0)
155 {
156 u8 item = (static_cast<u8>(in) & static_cast<u8>(0x7f));
157 T remainder = in >> 7;
158 bool finished = ! static_cast<bool>(remainder);
159 if (finished)
160 {
161 out += item;
162 break;
163 }
164 else
165 {
166 out += (item | static_cast<u8>(0x80));
167 --maxbytes;
168 in = remainder;
169 }
170 }
171}
172
173template <typename T>
174inline void
175insert_datum_uleb128(T in, string_queue & out)
176{
177 BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_signed == false);
178 size_t maxbytes = sizeof(T) + 1 + (sizeof(T) / 8);
179 while (maxbytes > 0)
180 {
181 u8 item = (static_cast<u8>(in) & static_cast<u8>(0x7f));
182 T remainder = in >> 7;
183 bool finished = ! static_cast<bool>(remainder);
184 if (finished)
185 {
186 out += item;
187 break;
188 }
189 else
190 {
191 out += (item | static_cast<u8>(0x80));
192 --maxbytes;
193 in = remainder;
194 }
195 }
196}
197
198template <typename T>
199inline T
200extract_datum_lsb(std::string const & in,
201 size_t & pos,
202 std::string const & name)
203{
204 size_t nbytes = sizeof(T);
205 T out = 0;
206 size_t shift = 0;
207
208 require_bytes(in, pos, nbytes, name);
209
210 while (nbytes > 0)
211 {
212 out |= widen<T,u8>(in[pos++]) << shift;
213 shift += 8;
214 --nbytes;
215 }
216 return out;
217}
218
219template <typename T>
220inline T
221extract_datum_lsb(string_queue const & in,
222 size_t & pos,
223 std::string const & name)
224{
225 size_t nbytes = sizeof(T);
226 T out = 0;
227 size_t shift = 0;
228
229 require_bytes(in, pos, nbytes, name);
230
231 while (nbytes > 0)
232 {
233 out |= widen<T,u8>(in[pos++]) << shift;
234 shift += 8;
235 --nbytes;
236 }
237 return out;
238}
239
240template <typename T>
241inline void
242insert_datum_lsb(T in, std::string & out)
243{
244 size_t const nbytes = sizeof(T);
245 char tmp[nbytes];
246 for (size_t i = 0; i < nbytes; ++i)
247 {
248 tmp[i] = static_cast<u8>(in) & static_cast<u8>(0xff);
249 in >>= 8;
250 }
251 out.append(std::string(tmp, tmp+nbytes));
252}
253
254template <typename T>
255inline void
256insert_datum_lsb(T in, string_queue & out)
257{
258 size_t const nbytes = sizeof(T);
259 char tmp[nbytes];
260 for (size_t i = 0; i < nbytes; ++i)
261 {
262 tmp[i] = static_cast<u8>(in) & static_cast<u8>(0xff);
263 in >>= 8;
264 }
265 out.append(std::string(tmp, tmp+nbytes));
266}
267
268inline void
269extract_variable_length_string(std::string const & buf,
270 std::string & out,
271 size_t & pos,
272 std::string const & name,
273 size_t maxlen = std::numeric_limits<size_t>::max())
274{
275 BOOST_STATIC_ASSERT(sizeof(std::string::size_type) == sizeof(size_t));
276 size_t len = extract_datum_uleb128<size_t>(buf, pos, name);
277 if (len > maxlen)
278 throw bad_decode(F("decoding variable length string of %d bytes for '%s', maximum is %d")
279 % len % name % maxlen);
280 require_bytes(buf, pos, len, name);
281 out.assign(buf, pos, len);
282 pos += len;
283}
284
285inline void
286insert_variable_length_string(std::string const & in,
287 std::string & buf)
288{
289 size_t len = in.size();
290 insert_datum_uleb128<size_t>(len, buf);
291 buf.append(in);
292}
293
294inline void
295insert_variable_length_string(std::string const & in,
296 string_queue & buf)
297{
298 size_t len = in.size();
299 insert_datum_uleb128<size_t>(len, buf);
300 buf.append(in);
301}
302
303inline std::string
304extract_substring(std::string const & buf,
305 size_t & pos,
306 size_t len,
307 std::string const & name)
308{
309 require_bytes(buf, pos, len, name);
310 std::string tmp = buf.substr(pos, len);
311 pos += len;
312 return tmp;
313}
314
315inline std::string
316extract_substring(string_queue const & buf,
317 size_t & pos,
318 size_t len,
319 std::string const & name)
320{
321 require_bytes(buf, pos, len, name);
322 std::string tmp = buf.substr(pos, len);
323 pos += len;
324 return tmp;
325}
326
327inline void
328assert_end_of_buffer(std::string const & str,
329 size_t pos,
330 std::string const & name)
331{
332 if (str.size() != pos)
333 throw bad_decode(F("expected %s to end at %d, have %d bytes")
334 % name % pos % str.size());
335}
336
337// Local Variables:
338// mode: C++
339// fill-column: 76
340// c-file-style: "gnu"
341// indent-tabs-mode: nil
342// End:
343// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
344
345#endif // __NETIO_HH__

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status