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