monotone

monotone Mtn Source Tree

Root/netcmd.cc

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

Archive Download this file

Branches

Tags

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