monotone

monotone Mtn Source Tree

Root/netcmd.cc

1// copyright (C) 2004 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <string>
7#include <vector>
8#include <utility>
9
10#include "adler32.hh"
11#include "constants.hh"
12#include "netcmd.hh"
13#include "netio.hh"
14#include "numeric_vocab.hh"
15#include "sanity.hh"
16#include "transforms.hh"
17#include "hmac.hh"
18
19using namespace std;
20
21static netcmd_item_type
22read_netcmd_item_type(string const & in,
23 size_t & pos,
24 string const & name)
25{
26 u8 tmp = extract_datum_lsb<u8>(in, pos, name);
27 switch (tmp)
28 {
29 case static_cast<u8>(revision_item):
30 return revision_item;
31 case static_cast<u8>(manifest_item):
32 return manifest_item;
33 case static_cast<u8>(file_item):
34 return file_item;
35 case static_cast<u8>(cert_item):
36 return cert_item;
37 case static_cast<u8>(key_item):
38 return key_item;
39 case static_cast<u8>(epoch_item):
40 return epoch_item;
41 default:
42 throw bad_decode(F("unknown item type 0x%x for '%s'")
43 % static_cast<int>(tmp) % name);
44 }
45}
46
47netcmd::netcmd() : version(constants::netcmd_current_protocol_version),
48 cmd_code(bye_cmd)
49{}
50
51size_t netcmd::encoded_size()
52{
53 string tmp;
54 insert_datum_uleb128<size_t>(payload.size(), tmp);
55 return 1 + 1 + tmp.size() + payload.size() + 4;
56}
57
58bool
59netcmd::operator==(netcmd const & other) const
60{
61 return version == other.version &&
62 cmd_code == other.cmd_code &&
63 payload == other.payload;
64}
65
66// note: usher_reply_cmd does not get included in the hmac.
67void
68netcmd::write(string & out, chained_hmac & hmac) const
69{
70 size_t oldlen = out.size();
71 out += static_cast<char>(version);
72 out += static_cast<char>(cmd_code);
73 insert_variable_length_string(payload, out);
74
75 if (cmd_code != usher_reply_cmd)
76 {
77 string digest = hmac.process(out, oldlen);
78 I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes);
79 out.append(digest);
80 }
81}
82
83// note: usher_cmd does not get included in the hmac.
84bool
85netcmd::read(string_queue & inbuf, chained_hmac & hmac)
86{
87 size_t pos = 0;
88
89 if (inbuf.size() < constants::netcmd_minsz)
90 return false;
91
92 u8 extracted_ver = extract_datum_lsb<u8>(inbuf, pos, "netcmd protocol number");
93 if (extracted_ver != version)
94 throw bad_decode(F("protocol version mismatch: wanted '%d' got '%d'")
95 % widen<u32,u8>(version)
96 % widen<u32,u8>(extracted_ver));
97 version = extracted_ver;
98
99 u8 cmd_byte = extract_datum_lsb<u8>(inbuf, pos, "netcmd code");
100 switch (cmd_byte)
101 {
102 case static_cast<u8>(hello_cmd):
103 case static_cast<u8>(anonymous_cmd):
104 case static_cast<u8>(auth_cmd):
105 case static_cast<u8>(error_cmd):
106 case static_cast<u8>(bye_cmd):
107 case static_cast<u8>(confirm_cmd):
108 case static_cast<u8>(refine_cmd):
109 case static_cast<u8>(done_cmd):
110 case static_cast<u8>(send_data_cmd):
111 case static_cast<u8>(send_delta_cmd):
112 case static_cast<u8>(data_cmd):
113 case static_cast<u8>(delta_cmd):
114 case static_cast<u8>(nonexistant_cmd):
115 case static_cast<u8>(usher_cmd):
116 cmd_code = static_cast<netcmd_code>(cmd_byte);
117 break;
118 default:
119 throw bad_decode(F("unknown netcmd code 0x%x") % widen<u32,u8>(cmd_byte));
120 }
121
122 // check to see if we have even enough bytes for a complete uleb128
123 size_t payload_len = 0;
124 if (!try_extract_datum_uleb128<size_t>(inbuf, pos, "netcmd payload length",
125 payload_len))
126 return false;
127
128 // they might have given us a bogus size
129 if (payload_len > constants::netcmd_payload_limit)
130 throw bad_decode(F("oversized payload of '%d' bytes") % payload_len);
131
132 // there might not be enough data yet in the input buffer
133 unsigned int minsize;
134 if (cmd_code == usher_cmd)
135 minsize = pos + payload_len;
136 else
137 minsize = pos + payload_len + constants::netsync_hmac_value_length_in_bytes;
138 if (inbuf.size() < minsize)
139 {
140 return false;
141 }
142
143 // grab it before the data gets munged
144 I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes);
145 string digest;
146 if (cmd_code != usher_cmd)
147 digest = hmac.process(inbuf, 0, pos + payload_len);
148
149 payload = extract_substring(inbuf, pos, payload_len, "netcmd payload");
150
151 // they might have given us bogus data
152 string cmd_digest;
153 if (cmd_code != usher_cmd)
154 cmd_digest = extract_substring(inbuf, pos,
155 constants::netsync_hmac_value_length_in_bytes,
156 "netcmd HMAC");
157 inbuf.pop_front(pos);
158 if (cmd_digest != digest)
159 throw bad_decode(F("bad HMAC checksum (got %s, wanted %s)\n"
160 "this suggests data was corrupted in transit\n")
161 % encode_hexenc(cmd_digest)
162 % encode_hexenc(digest));
163
164 return true;
165}
166
167////////////////////////////////////////////
168// payload reader/writer functions follow //
169////////////////////////////////////////////
170
171void
172netcmd::read_error_cmd(std::string & errmsg) const
173{
174 size_t pos = 0;
175 // syntax is: <errmsg:vstr>
176 extract_variable_length_string(payload, errmsg, pos, "error netcmd, message");
177 assert_end_of_buffer(payload, pos, "error netcmd payload");
178}
179
180void
181netcmd::write_error_cmd(std::string const & errmsg)
182{
183 cmd_code = error_cmd;
184 payload.clear();
185 insert_variable_length_string(errmsg, payload);
186}
187
188
189void
190netcmd::read_hello_cmd(rsa_keypair_id & server_keyname,
191 rsa_pub_key & server_key,
192 id & nonce) const
193{
194 size_t pos = 0;
195 // syntax is: <server keyname:vstr> <server pubkey:vstr> <nonce:20 random bytes>
196 string skn_str, sk_str;
197 extract_variable_length_string(payload, skn_str, pos,
198 "hello netcmd, server key name");
199 server_keyname = rsa_keypair_id(skn_str);
200 extract_variable_length_string(payload, sk_str, pos,
201 "hello netcmd, server key");
202 server_key = rsa_pub_key(sk_str);
203 nonce = id(extract_substring(payload, pos,
204 constants::merkle_hash_length_in_bytes,
205 "hello netcmd, nonce"));
206 assert_end_of_buffer(payload, pos, "hello netcmd payload");
207}
208
209void
210netcmd::write_hello_cmd(rsa_keypair_id const & server_keyname,
211 rsa_pub_key const & server_key,
212 id const & nonce)
213{
214 cmd_code = hello_cmd;
215 payload.clear();
216 I(nonce().size() == constants::merkle_hash_length_in_bytes);
217 insert_variable_length_string(server_keyname(), payload);
218 insert_variable_length_string(server_key(), payload);
219 payload += nonce();
220}
221
222
223void
224netcmd::read_anonymous_cmd(protocol_role & role,
225 utf8 & include_pattern,
226 utf8 & exclude_pattern,
227 rsa_oaep_sha_data & hmac_key_encrypted) const
228{
229 size_t pos = 0;
230 // syntax is: <role:1 byte> <include_pattern: vstr> <exclude_pattern: vstr> <hmac_key_encrypted: vstr>
231 u8 role_byte = extract_datum_lsb<u8>(payload, pos, "anonymous(hmac) netcmd, role");
232 if (role_byte != static_cast<u8>(source_role)
233 && role_byte != static_cast<u8>(sink_role)
234 && role_byte != static_cast<u8>(source_and_sink_role))
235 throw bad_decode(F("unknown role specifier %d") % widen<u32,u8>(role_byte));
236 role = static_cast<protocol_role>(role_byte);
237 std::string pattern_string;
238 extract_variable_length_string(payload, pattern_string, pos,
239 "anonymous(hmac) netcmd, include_pattern");
240 include_pattern = utf8(pattern_string);
241 extract_variable_length_string(payload, pattern_string, pos,
242 "anonymous(hmac) netcmd, exclude_pattern");
243 exclude_pattern = utf8(pattern_string);
244 string hmac_key_string;
245 extract_variable_length_string(payload, hmac_key_string, pos,
246 "anonymous(hmac) netcmd, hmac_key_encrypted");
247 hmac_key_encrypted = rsa_oaep_sha_data(hmac_key_string);
248 assert_end_of_buffer(payload, pos, "anonymous(hmac) netcmd payload");
249}
250
251void
252netcmd::write_anonymous_cmd(protocol_role role,
253 utf8 const & include_pattern,
254 utf8 const & exclude_pattern,
255 rsa_oaep_sha_data const & hmac_key_encrypted)
256{
257 cmd_code = anonymous_cmd;
258 payload = static_cast<char>(role);
259 insert_variable_length_string(include_pattern(), payload);
260 insert_variable_length_string(exclude_pattern(), payload);
261 insert_variable_length_string(hmac_key_encrypted(), payload);
262}
263
264void
265netcmd::read_auth_cmd(protocol_role & role,
266 utf8 & include_pattern,
267 utf8 & exclude_pattern,
268 id & client,
269 id & nonce1,
270 rsa_oaep_sha_data & hmac_key_encrypted,
271 string & signature) const
272{
273 size_t pos = 0;
274 // syntax is: <role:1 byte> <include_pattern: vstr> <exclude_pattern: vstr>
275 // <client: 20 bytes sha1> <nonce1: 20 random bytes>
276 // <hmac_key_encrypted: vstr> <signature: vstr>
277 u8 role_byte = extract_datum_lsb<u8>(payload, pos, "auth netcmd, role");
278 if (role_byte != static_cast<u8>(source_role)
279 && role_byte != static_cast<u8>(sink_role)
280 && role_byte != static_cast<u8>(source_and_sink_role))
281 throw bad_decode(F("unknown role specifier %d") % widen<u32,u8>(role_byte));
282 role = static_cast<protocol_role>(role_byte);
283 std::string pattern_string;
284 extract_variable_length_string(payload, pattern_string, pos,
285 "auth(hmac) netcmd, include_pattern");
286 include_pattern = utf8(pattern_string);
287 extract_variable_length_string(payload, pattern_string, pos,
288 "auth(hmac) netcmd, exclude_pattern");
289 exclude_pattern = utf8(pattern_string);
290 client = id(extract_substring(payload, pos,
291 constants::merkle_hash_length_in_bytes,
292 "auth(hmac) netcmd, client identifier"));
293 nonce1 = id(extract_substring(payload, pos,
294 constants::merkle_hash_length_in_bytes,
295 "auth(hmac) netcmd, nonce1"));
296 string hmac_key;
297 extract_variable_length_string(payload, hmac_key, pos,
298 "auth(hmac) netcmd, hmac_key_encrypted");
299 hmac_key_encrypted = rsa_oaep_sha_data(hmac_key);
300 extract_variable_length_string(payload, signature, pos,
301 "auth(hmac) netcmd, signature");
302 assert_end_of_buffer(payload, pos, "auth(hmac) netcmd payload");
303}
304
305void
306netcmd::write_auth_cmd(protocol_role role,
307 utf8 const & include_pattern,
308 utf8 const & exclude_pattern,
309 id const & client,
310 id const & nonce1,
311 rsa_oaep_sha_data const & hmac_key_encrypted,
312 string const & signature)
313{
314 cmd_code = auth_cmd;
315 I(client().size() == constants::merkle_hash_length_in_bytes);
316 I(nonce1().size() == constants::merkle_hash_length_in_bytes);
317 payload = static_cast<char>(role);
318 insert_variable_length_string(include_pattern(), payload);
319 insert_variable_length_string(exclude_pattern(), payload);
320 payload += client();
321 payload += nonce1();
322 insert_variable_length_string(hmac_key_encrypted(), payload);
323 insert_variable_length_string(signature, payload);
324}
325
326void
327netcmd::read_confirm_cmd() const
328{
329 size_t pos = 0;
330 assert_end_of_buffer(payload, pos, "confirm netcmd payload");
331}
332
333void
334netcmd::write_confirm_cmd()
335{
336 cmd_code = confirm_cmd;
337 payload.clear();
338}
339
340void
341netcmd::read_refine_cmd(merkle_node & node) const
342{
343 // syntax is: <node: a merkle tree node>
344 read_node(payload, node);
345}
346
347void
348netcmd::write_refine_cmd(merkle_node const & node)
349{
350 cmd_code = refine_cmd;
351 payload.clear();
352 write_node(node, payload);
353}
354
355void
356netcmd::read_done_cmd(size_t & level, netcmd_item_type & type) const
357{
358 size_t pos = 0;
359 // syntax is: <level: uleb128> <type: 1 byte>
360 level = extract_datum_uleb128<size_t>(payload, pos,
361 "done netcmd, level number");
362 type = read_netcmd_item_type(payload, pos, "done netcmd, item type");
363 assert_end_of_buffer(payload, pos, "done netcmd payload");
364}
365
366void
367netcmd::write_done_cmd(size_t level,
368 netcmd_item_type type)
369{
370 cmd_code = done_cmd;
371 payload.clear();
372 insert_datum_uleb128<size_t>(level, payload);
373 payload += static_cast<char>(type);
374}
375
376void
377netcmd::read_send_data_cmd(netcmd_item_type & type, id & item) const
378{
379 size_t pos = 0;
380 // syntax is: <type: 1 byte> <id: 20 bytes sha1>
381 type = read_netcmd_item_type(payload, pos, "send_data netcmd, item type");
382 item = id(extract_substring(payload, pos,
383 constants::merkle_hash_length_in_bytes,
384 "send_data netcmd, item identifier"));
385 assert_end_of_buffer(payload, pos, "send_data netcmd payload");
386}
387
388void
389netcmd::write_send_data_cmd(netcmd_item_type type, id const & item)
390{
391 cmd_code = send_data_cmd;
392 I(item().size() == constants::merkle_hash_length_in_bytes);
393 payload = static_cast<char>(type);
394 payload += item();
395}
396
397void
398netcmd::read_send_delta_cmd(netcmd_item_type & type,
399 id & base,
400 id & ident) const
401{
402 size_t pos = 0;
403 // syntax is: <type: 1 byte> <src: 20 bytes sha1> <dst: 20 bytes sha1>
404 type = read_netcmd_item_type(payload, pos, "send_delta netcmd, item type");
405 base = id(extract_substring(payload, pos,
406 constants::merkle_hash_length_in_bytes,
407 "send_delta netcmd, base item identifier"));
408 ident = id(extract_substring(payload, pos,
409 constants::merkle_hash_length_in_bytes,
410 "send_delta netcmd, ident item identifier"));
411 assert_end_of_buffer(payload, pos, "send_delta netcmd payload");
412}
413
414void
415netcmd::write_send_delta_cmd(netcmd_item_type type,
416 id const & base,
417 id const & ident)
418{
419 cmd_code = send_delta_cmd;
420 I(base().size() == constants::merkle_hash_length_in_bytes);
421 I(ident().size() == constants::merkle_hash_length_in_bytes);
422 payload = static_cast<char>(type);
423 payload += base();
424 payload += ident();
425}
426
427void
428netcmd::read_data_cmd(netcmd_item_type & type,
429 id & item, string & dat) const
430{
431 size_t pos = 0;
432 // syntax is: <type: 1 byte> <id: 20 bytes sha1>
433 // <compressed_p1: 1 byte> <dat: vstr>
434
435 type = read_netcmd_item_type(payload, pos, "data netcmd, item type");
436 item = id(extract_substring(payload, pos,
437 constants::merkle_hash_length_in_bytes,
438 "data netcmd, item identifier"));
439
440 dat.clear();
441 u8 compressed_p = extract_datum_lsb<u8>(payload, pos,
442 "data netcmd, compression flag");
443 extract_variable_length_string(payload, dat, pos,
444 "data netcmd, data payload");
445 if (compressed_p == 1)
446 {
447 gzip<data> zdat(dat);
448 data tdat;
449 decode_gzip(zdat, tdat);
450 dat = tdat();
451 }
452 assert_end_of_buffer(payload, pos, "data netcmd payload");
453}
454
455void
456netcmd::write_data_cmd(netcmd_item_type type,
457 id const & item,
458 string const & dat)
459{
460 cmd_code = data_cmd;
461 I(item().size() == constants::merkle_hash_length_in_bytes);
462 payload = static_cast<char>(type);
463 payload += item();
464 if (dat.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
465 {
466 gzip<data> zdat;
467 encode_gzip(dat, zdat);
468 payload += static_cast<char>(1); // compressed flag
469 insert_variable_length_string(zdat(), payload);
470 }
471 else
472 {
473 payload += static_cast<char>(0); // compressed flag
474 insert_variable_length_string(dat, payload);
475 }
476}
477
478
479void
480netcmd::read_delta_cmd(netcmd_item_type & type,
481 id & base, id & ident, delta & del) const
482{
483 size_t pos = 0;
484 // syntax is: <type: 1 byte> <src: 20 bytes sha1> <dst: 20 bytes sha1>
485 // <compressed_p: 1 byte> <del: vstr>
486 type = read_netcmd_item_type(payload, pos, "delta netcmd, item type");
487 base = id(extract_substring(payload, pos,
488 constants::merkle_hash_length_in_bytes,
489 "delta netcmd, base identifier"));
490 ident = id(extract_substring(payload, pos,
491 constants::merkle_hash_length_in_bytes,
492 "delta netcmd, ident identifier"));
493 u8 compressed_p = extract_datum_lsb<u8>(payload, pos,
494 "delta netcmd, compression flag");
495 string tmp;
496 extract_variable_length_string(payload, tmp, pos,
497 "delta netcmd, delta payload");
498 if (compressed_p == 1)
499 {
500 gzip<delta> zdel(tmp);
501 decode_gzip(zdel, del);
502 }
503 else
504 {
505 del = tmp;
506 }
507 assert_end_of_buffer(payload, pos, "delta netcmd payload");
508}
509
510void
511netcmd::write_delta_cmd(netcmd_item_type & type,
512 id const & base, id const & ident,
513 delta const & del)
514{
515 cmd_code = delta_cmd;
516 I(base().size() == constants::merkle_hash_length_in_bytes);
517 I(ident().size() == constants::merkle_hash_length_in_bytes);
518 payload = static_cast<char>(type);
519 payload += base();
520 payload += ident();
521
522 string tmp;
523
524 if (tmp.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
525 {
526 payload += static_cast<char>(1); // compressed flag
527 gzip<delta> zdel;
528 encode_gzip(del, zdel);
529 tmp = zdel();
530 }
531 else
532 {
533 payload += static_cast<char>(0); // compressed flag
534 tmp = del();
535 }
536 I(tmp.size() <= constants::netcmd_payload_limit);
537 insert_variable_length_string(tmp, payload);
538}
539
540
541void
542netcmd::read_nonexistant_cmd(netcmd_item_type & type, id & item) const
543{
544 size_t pos = 0;
545 // syntax is: <type: 1 byte> <id: 20 bytes sha1>
546 type = read_netcmd_item_type(payload, pos, "nonexistant netcmd, item type");
547 item = id(extract_substring(payload, pos,
548 constants::merkle_hash_length_in_bytes,
549 "nonexistant netcmd, item identifier"));
550 assert_end_of_buffer(payload, pos, "nonexistant netcmd payload");
551}
552
553void
554netcmd::write_nonexistant_cmd(netcmd_item_type type, id const & item)
555{
556 cmd_code = nonexistant_cmd;
557 I(item().size() == constants::merkle_hash_length_in_bytes);
558 payload = static_cast<char>(type);
559 payload += item();
560}
561
562void
563netcmd::read_usher_cmd(utf8 & greeting) const
564{
565 size_t pos = 0;
566 std::string str;
567 extract_variable_length_string(payload, str, pos, "error netcmd, message");
568 greeting = utf8(str);
569 assert_end_of_buffer(payload, pos, "error netcmd payload");
570}
571
572void
573netcmd::write_usher_reply_cmd(utf8 const & server, utf8 const & pattern)
574{
575 cmd_code = usher_reply_cmd;
576 payload.clear();
577 insert_variable_length_string(server(), payload);
578 insert_variable_length_string(pattern(), payload);
579}
580
581
582#ifdef BUILD_UNIT_TESTS
583
584#include "unit_tests.hh"
585#include "transforms.hh"
586#include <boost/lexical_cast.hpp>
587
588void
589test_netcmd_mac()
590{
591 netcmd out_cmd, in_cmd;
592 string buf;
593 netsync_session_key key(constants::netsync_key_initializer);
594 {
595 chained_hmac mac(key);
596 // mutates mac
597 out_cmd.write(buf, mac);
598 BOOST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
599 }
600
601 {
602 chained_hmac mac(key);
603 out_cmd.write(buf, mac);
604 }
605 buf[0] ^= 0xff;
606 {
607 chained_hmac mac(key);
608 BOOST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
609 }
610
611 {
612 chained_hmac mac(key);
613 out_cmd.write(buf, mac);
614 }
615 buf[buf.size() - 1] ^= 0xff;
616 {
617 chained_hmac mac(key);
618 BOOST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
619 }
620
621 {
622 chained_hmac mac(key);
623 out_cmd.write(buf, mac);
624 }
625 buf += '\0';
626 {
627 chained_hmac mac(key);
628 BOOST_CHECK_THROW(in_cmd.read_string(buf, mac), bad_decode);
629 }
630}
631
632static void
633do_netcmd_roundtrip(netcmd const & out_cmd, netcmd & in_cmd, string & buf)
634{
635 netsync_session_key key(constants::netsync_key_initializer);
636 {
637 chained_hmac mac(key);
638 out_cmd.write(buf, mac);
639 }
640 {
641 chained_hmac mac(key);
642 BOOST_CHECK(in_cmd.read_string(buf, mac));
643 }
644 BOOST_CHECK(in_cmd == out_cmd);
645}
646
647void
648test_netcmd_functions()
649{
650
651 try
652 {
653
654 // error_cmd
655 {
656 L(boost::format("checking i/o round trip on error_cmd\n"));
657 netcmd out_cmd, in_cmd;
658 string out_errmsg("your shoelaces are untied"), in_errmsg;
659 string buf;
660 out_cmd.write_error_cmd(out_errmsg);
661 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
662 in_cmd.read_error_cmd(in_errmsg);
663 BOOST_CHECK(in_errmsg == out_errmsg);
664 L(boost::format("errmsg_cmd test done, buffer was %d bytes\n") % buf.size());
665 }
666
667 // bye_cmd
668 {
669 L(boost::format("checking i/o round trip on bye_cmd\n"));
670 netcmd out_cmd, in_cmd;
671 string buf;
672 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
673 L(boost::format("bye_cmd test done, buffer was %d bytes\n") % buf.size());
674 }
675
676 // hello_cmd
677 {
678 L(boost::format("checking i/o round trip on hello_cmd\n"));
679 netcmd out_cmd, in_cmd;
680 string buf;
681 rsa_keypair_id out_server_keyname("server@there"), in_server_keyname;
682 rsa_pub_key out_server_key("9387938749238792874"), in_server_key;
683 id out_nonce(raw_sha1("nonce it up")), in_nonce;
684 out_cmd.write_hello_cmd(out_server_keyname, out_server_key, out_nonce);
685 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
686 in_cmd.read_hello_cmd(in_server_keyname, in_server_key, in_nonce);
687 BOOST_CHECK(in_server_keyname == out_server_keyname);
688 BOOST_CHECK(in_server_key == out_server_key);
689 BOOST_CHECK(in_nonce == out_nonce);
690 L(boost::format("hello_cmd test done, buffer was %d bytes\n") % buf.size());
691 }
692
693 // anonymous_cmd
694 {
695 L(boost::format("checking i/o round trip on anonymous_cmd\n"));
696 netcmd out_cmd, in_cmd;
697 protocol_role out_role = source_and_sink_role, in_role;
698 string buf;
699 // total cheat, since we don't actually verify that rsa_oaep_sha_data
700 // is sensible anywhere here...
701 rsa_oaep_sha_data out_key("nonce start my heart"), in_key;
702 utf8 out_include_pattern("radishes galore!"), in_include_pattern;
703 utf8 out_exclude_pattern("turnips galore!"), in_exclude_pattern;
704
705 out_cmd.write_anonymous_cmd(out_role, out_include_pattern, out_exclude_pattern, out_key);
706 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
707 in_cmd.read_anonymous_cmd(in_role, in_include_pattern, in_exclude_pattern, in_key);
708 BOOST_CHECK(in_key == out_key);
709 BOOST_CHECK(in_include_pattern == out_include_pattern);
710 BOOST_CHECK(in_exclude_pattern == out_exclude_pattern);
711 BOOST_CHECK(in_role == out_role);
712 L(boost::format("anonymous_cmd test done, buffer was %d bytes\n") % buf.size());
713 }
714
715 // auth_cmd
716 {
717 L(boost::format("checking i/o round trip on auth_cmd\n"));
718 netcmd out_cmd, in_cmd;
719 protocol_role out_role = source_and_sink_role, in_role;
720 string buf;
721 id out_client(raw_sha1("happy client day")), out_nonce1(raw_sha1("nonce me amadeus")),
722 in_client, in_nonce1;
723 // total cheat, since we don't actually verify that rsa_oaep_sha_data
724 // is sensible anywhere here...
725 rsa_oaep_sha_data out_key("nonce start my heart"), in_key;
726 string out_signature(raw_sha1("burble") + raw_sha1("gorby")), in_signature;
727 utf8 out_include_pattern("radishes galore!"), in_include_pattern;
728 utf8 out_exclude_pattern("turnips galore!"), in_exclude_pattern;
729
730 out_cmd.write_auth_cmd(out_role, out_include_pattern, out_exclude_pattern
731 , out_client, out_nonce1, out_key, out_signature);
732 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
733 in_cmd.read_auth_cmd(in_role, in_include_pattern, in_exclude_pattern,
734 in_client, in_nonce1, in_key, in_signature);
735 BOOST_CHECK(in_client == out_client);
736 BOOST_CHECK(in_nonce1 == out_nonce1);
737 BOOST_CHECK(in_key == out_key);
738 BOOST_CHECK(in_signature == out_signature);
739 BOOST_CHECK(in_role == out_role);
740 BOOST_CHECK(in_include_pattern == out_include_pattern);
741 BOOST_CHECK(in_exclude_pattern == out_exclude_pattern);
742 L(boost::format("auth_cmd test done, buffer was %d bytes\n") % buf.size());
743 }
744
745 // confirm_cmd
746 {
747 L(boost::format("checking i/o round trip on confirm_cmd\n"));
748 netcmd out_cmd, in_cmd;
749 string buf;
750 out_cmd.write_confirm_cmd();
751 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
752 in_cmd.read_confirm_cmd();
753 L(boost::format("confirm_cmd test done, buffer was %d bytes\n") % buf.size());
754 }
755
756 // refine_cmd
757 {
758 L(boost::format("checking i/o round trip on refine_cmd\n"));
759 netcmd out_cmd, in_cmd;
760 string buf;
761 merkle_node out_node, in_node;
762
763 out_node.set_raw_slot(0, id(raw_sha1("The police pulled Kris Kringle over")));
764 out_node.set_raw_slot(3, id(raw_sha1("Kris Kringle tried to escape from the police")));
765 out_node.set_raw_slot(8, id(raw_sha1("He was arrested for auto theft")));
766 out_node.set_raw_slot(15, id(raw_sha1("He was whisked away to jail")));
767 out_node.set_slot_state(0, subtree_state);
768 out_node.set_slot_state(3, live_leaf_state);
769 out_node.set_slot_state(8, dead_leaf_state);
770 out_node.set_slot_state(15, subtree_state);
771
772 out_cmd.write_refine_cmd(out_node);
773 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
774 in_cmd.read_refine_cmd(in_node);
775 BOOST_CHECK(in_node == out_node);
776 L(boost::format("refine_cmd test done, buffer was %d bytes\n") % buf.size());
777 }
778
779 // done_cmd
780 {
781 L(boost::format("checking i/o round trip on done_cmd\n"));
782 netcmd out_cmd, in_cmd;
783 size_t out_level(12), in_level;
784 netcmd_item_type out_type(key_item), in_type(manifest_item);
785 string buf;
786
787 out_cmd.write_done_cmd(out_level, out_type);
788 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
789 in_cmd.read_done_cmd(in_level, in_type);
790 BOOST_CHECK(in_level == out_level);
791 BOOST_CHECK(in_type == out_type);
792 L(boost::format("done_cmd test done, buffer was %d bytes\n") % buf.size());
793 }
794
795 // send_data_cmd
796 {
797 L(boost::format("checking i/o round trip on send_data_cmd\n"));
798 netcmd out_cmd, in_cmd;
799 netcmd_item_type out_type(file_item), in_type(key_item);
800 id out_id(raw_sha1("avocado is the yummiest")), in_id;
801 string buf;
802
803 out_cmd.write_send_data_cmd(out_type, out_id);
804 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
805 in_cmd.read_send_data_cmd(in_type, in_id);
806 BOOST_CHECK(in_type == out_type);
807 BOOST_CHECK(in_id == out_id);
808 L(boost::format("send_data_cmd test done, buffer was %d bytes\n") % buf.size());
809 }
810
811 // send_delta_cmd
812 {
813 L(boost::format("checking i/o round trip on send_delta_cmd\n"));
814 netcmd out_cmd, in_cmd;
815 netcmd_item_type out_type(file_item), in_type(key_item);
816 id out_head(raw_sha1("when you board an airplane")), in_head;
817 id out_base(raw_sha1("always check the exit locations")), in_base;
818 string buf;
819
820 out_cmd.write_send_delta_cmd(out_type, out_head, out_base);
821 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
822 in_cmd.read_send_delta_cmd(in_type, in_head, in_base);
823 BOOST_CHECK(in_type == out_type);
824 BOOST_CHECK(in_head == out_head);
825 BOOST_CHECK(in_base == out_base);
826 L(boost::format("send_delta_cmd test done, buffer was %d bytes\n") % buf.size());
827 }
828
829 // data_cmd
830 {
831 L(boost::format("checking i/o round trip on data_cmd\n"));
832 netcmd out_cmd, in_cmd;
833 netcmd_item_type out_type(file_item), in_type(key_item);
834 id out_id(raw_sha1("tuna is not yummy")), in_id;
835 string out_dat("thank you for flying northwest"), in_dat;
836 string buf;
837 out_cmd.write_data_cmd(out_type, out_id, out_dat);
838 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
839 in_cmd.read_data_cmd(in_type, in_id, in_dat);
840 BOOST_CHECK(in_id == out_id);
841 BOOST_CHECK(in_dat == out_dat);
842 L(boost::format("data_cmd test done, buffer was %d bytes\n") % buf.size());
843 }
844
845 // delta_cmd
846 {
847 L(boost::format("checking i/o round trip on delta_cmd\n"));
848 netcmd out_cmd, in_cmd;
849 netcmd_item_type out_type(file_item), in_type(key_item);
850 id out_head(raw_sha1("your seat cusion can be reused")), in_head;
851 id out_base(raw_sha1("as a floatation device")), in_base;
852 delta out_delta("goodness, this is not an xdelta"), in_delta;
853 string buf;
854
855 out_cmd.write_delta_cmd(out_type, out_head, out_base, out_delta);
856 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
857 in_cmd.read_delta_cmd(in_type, in_head, in_base, in_delta);
858 BOOST_CHECK(in_type == out_type);
859 BOOST_CHECK(in_head == out_head);
860 BOOST_CHECK(in_base == out_base);
861 BOOST_CHECK(in_delta == out_delta);
862 L(boost::format("delta_cmd test done, buffer was %d bytes\n") % buf.size());
863 }
864
865 // nonexistant_cmd
866 {
867 L(boost::format("checking i/o round trip on nonexistant_cmd\n"));
868 netcmd out_cmd, in_cmd;
869 netcmd_item_type out_type(file_item), in_type(key_item);
870 id out_id(raw_sha1("avocado is the yummiest")), in_id;
871 string buf;
872
873 out_cmd.write_nonexistant_cmd(out_type, out_id);
874 do_netcmd_roundtrip(out_cmd, in_cmd, buf);
875 in_cmd.read_nonexistant_cmd(in_type, in_id);
876 BOOST_CHECK(in_type == out_type);
877 BOOST_CHECK(in_id == out_id);
878 L(boost::format("nonexistant_cmd test done, buffer was %d bytes\n") % buf.size());
879 }
880
881 }
882 catch (bad_decode & d)
883 {
884 L(boost::format("bad decode exception: '%s'\n") % d.what);
885 throw;
886 }
887}
888
889void
890add_netcmd_tests(test_suite * suite)
891{
892 suite->add(BOOST_TEST_CASE(&test_netcmd_functions));
893 suite->add(BOOST_TEST_CASE(&test_netcmd_mac));
894}
895
896#endif // BUILD_UNIT_TESTS

Archive Download this file

Branches

Tags

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